/*****************************************************************************
 * This file is part of uvg266 VVC encoder.
 *
 * Copyright (c) 2021, Tampere University, ITU/ISO/IEC, project contributors
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 * 
 * * Redistributions of source code must retain the above copyright notice, this
 *   list of conditions and the following disclaimer.
 * 
 * * Redistributions in binary form must reproduce the above copyright notice, this
 *   list of conditions and the following disclaimer in the documentation and/or
 *   other materials provided with the distribution.
 * 
 * * Neither the name of the Tampere University or ITU/ISO/IEC nor the names of its
 *   contributors may be used to endorse or promote products derived from
 *   this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * INCLUDING NEGLIGENCE OR OTHERWISE ARISING IN ANY WAY OUT OF THE USE OF THIS
 ****************************************************************************/

#include "strategies/generic/dct-generic.h"

#include "strategyselector.h"
#include "tables.h"

ALIGNED(32) const int16_t uvg_g_dst_4[4][4] =
{
  { 29, 55, 74, 84 },
  { 74, 74, 0, -74 },
  { 84, -29, -74, 55 },
  { 55, -84, 74, -29 }
};

ALIGNED(32) const int16_t uvg_g_dct_2[2][2] =
{
  {64, 64,  },
  {64, -64,  },
};

ALIGNED(32) const int16_t uvg_g_dct_4[4][4] =
{
  { 64, 64, 64, 64 },
  { 83, 36, -36, -83 },
  { 64, -64, -64, 64 },
  { 36, -83, 83, -36 }
};

ALIGNED(64) const int16_t uvg_g_dct_8[8][8] =
{
  { 64, 64, 64, 64, 64, 64, 64, 64 },
  { 89, 75, 50, 18, -18, -50, -75, -89 },
  { 83, 36, -36, -83, -83, -36, 36, 83 },
  { 75, -18, -89, -50, 50, 89, 18, -75 },
  { 64, -64, -64, 64, 64, -64, -64, 64 },
  { 50, -89, 18, 75, -75, -18, 89, -50 },
  { 36, -83, 83, -36, -36, 83, -83, 36 },
  { 18, -50, 75, -89, 89, -75, 50, -18 }
};

ALIGNED(64) const int16_t uvg_g_dct_16[16][16] =
{
  { 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 },
  { 90, 87, 80, 70, 57, 43, 25, 9, -9, -25, -43, -57, -70, -80, -87, -90 },
  { 89, 75, 50, 18, -18, -50, -75, -89, -89, -75, -50, -18, 18, 50, 75, 89 },
  { 87, 57, 9, -43, -80, -90, -70, -25, 25, 70, 90, 80, 43, -9, -57, -87 },
  { 83, 36, -36, -83, -83, -36, 36, 83, 83, 36, -36, -83, -83, -36, 36, 83 },
  { 80, 9, -70, -87, -25, 57, 90, 43, -43, -90, -57, 25, 87, 70, -9, -80 },
  { 75, -18, -89, -50, 50, 89, 18, -75, -75, 18, 89, 50, -50, -89, -18, 75 },
  { 70, -43, -87, 9, 90, 25, -80, -57, 57, 80, -25, -90, -9, 87, 43, -70 },
  { 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64 },
  { 57, -80, -25, 90, -9, -87, 43, 70, -70, -43, 87, 9, -90, 25, 80, -57 },
  { 50, -89, 18, 75, -75, -18, 89, -50, -50, 89, -18, -75, 75, 18, -89, 50 },
  { 43, -90, 57, 25, -87, 70, 9, -80, 80, -9, -70, 87, -25, -57, 90, -43 },
  { 36, -83, 83, -36, -36, 83, -83, 36, 36, -83, 83, -36, -36, 83, -83, 36 },
  { 25, -70, 90, -80, 43, 9, -57, 87, -87, 57, -9, -43, 80, -90, 70, -25 },
  { 18, -50, 75, -89, 89, -75, 50, -18, -18, 50, -75, 89, -89, 75, -50, 18 },
  { 9, -25, 43, -57, 70, -80, 87, -90, 90, -87, 80, -70, 57, -43, 25, -9 }
};

ALIGNED(64) const int16_t uvg_g_dct_32[32][32] =
{
  { 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 },
  { 90, 90, 88, 85, 82, 78, 73, 67, 61, 54, 46, 38, 31, 22, 13, 4, -4, -13, -22, -31, -38, -46, -54, -61, -67, -73, -78, -82, -85, -88, -90, -90 },
  { 90, 87, 80, 70, 57, 43, 25, 9, -9, -25, -43, -57, -70, -80, -87, -90, -90, -87, -80, -70, -57, -43, -25, -9, 9, 25, 43, 57, 70, 80, 87, 90 },
  { 90, 82, 67, 46, 22, -4, -31, -54, -73, -85, -90, -88, -78, -61, -38, -13, 13, 38, 61, 78, 88, 90, 85, 73, 54, 31, 4, -22, -46, -67, -82, -90 },
  { 89, 75, 50, 18, -18, -50, -75, -89, -89, -75, -50, -18, 18, 50, 75, 89, 89, 75, 50, 18, -18, -50, -75, -89, -89, -75, -50, -18, 18, 50, 75, 89 },
  { 88, 67, 31, -13, -54, -82, -90, -78, -46, -4, 38, 73, 90, 85, 61, 22, -22, -61, -85, -90, -73, -38, 4, 46, 78, 90, 82, 54, 13, -31, -67, -88 },
  { 87, 57, 9, -43, -80, -90, -70, -25, 25, 70, 90, 80, 43, -9, -57, -87, -87, -57, -9, 43, 80, 90, 70, 25, -25, -70, -90, -80, -43, 9, 57, 87 },
  { 85, 46, -13, -67, -90, -73, -22, 38, 82, 88, 54, -4, -61, -90, -78, -31, 31, 78, 90, 61, 4, -54, -88, -82, -38, 22, 73, 90, 67, 13, -46, -85 },
  { 83, 36, -36, -83, -83, -36, 36, 83, 83, 36, -36, -83, -83, -36, 36, 83, 83, 36, -36, -83, -83, -36, 36, 83, 83, 36, -36, -83, -83, -36, 36, 83 },
  { 82, 22, -54, -90, -61, 13, 78, 85, 31, -46, -90, -67, 4, 73, 88, 38, -38, -88, -73, -4, 67, 90, 46, -31, -85, -78, -13, 61, 90, 54, -22, -82 },
  { 80, 9, -70, -87, -25, 57, 90, 43, -43, -90, -57, 25, 87, 70, -9, -80, -80, -9, 70, 87, 25, -57, -90, -43, 43, 90, 57, -25, -87, -70, 9, 80 },
  { 78, -4, -82, -73, 13, 85, 67, -22, -88, -61, 31, 90, 54, -38, -90, -46, 46, 90, 38, -54, -90, -31, 61, 88, 22, -67, -85, -13, 73, 82, 4, -78 },
  { 75, -18, -89, -50, 50, 89, 18, -75, -75, 18, 89, 50, -50, -89, -18, 75, 75, -18, -89, -50, 50, 89, 18, -75, -75, 18, 89, 50, -50, -89, -18, 75 },
  { 73, -31, -90, -22, 78, 67, -38, -90, -13, 82, 61, -46, -88, -4, 85, 54, -54, -85, 4, 88, 46, -61, -82, 13, 90, 38, -67, -78, 22, 90, 31, -73 },
  { 70, -43, -87, 9, 90, 25, -80, -57, 57, 80, -25, -90, -9, 87, 43, -70, -70, 43, 87, -9, -90, -25, 80, 57, -57, -80, 25, 90, 9, -87, -43, 70 },
  { 67, -54, -78, 38, 85, -22, -90, 4, 90, 13, -88, -31, 82, 46, -73, -61, 61, 73, -46, -82, 31, 88, -13, -90, -4, 90, 22, -85, -38, 78, 54, -67 },
  { 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64 },
  { 61, -73, -46, 82, 31, -88, -13, 90, -4, -90, 22, 85, -38, -78, 54, 67, -67, -54, 78, 38, -85, -22, 90, 4, -90, 13, 88, -31, -82, 46, 73, -61 },
  { 57, -80, -25, 90, -9, -87, 43, 70, -70, -43, 87, 9, -90, 25, 80, -57, -57, 80, 25, -90, 9, 87, -43, -70, 70, 43, -87, -9, 90, -25, -80, 57 },
  { 54, -85, -4, 88, -46, -61, 82, 13, -90, 38, 67, -78, -22, 90, -31, -73, 73, 31, -90, 22, 78, -67, -38, 90, -13, -82, 61, 46, -88, 4, 85, -54 },
  { 50, -89, 18, 75, -75, -18, 89, -50, -50, 89, -18, -75, 75, 18, -89, 50, 50, -89, 18, 75, -75, -18, 89, -50, -50, 89, -18, -75, 75, 18, -89, 50 },
  { 46, -90, 38, 54, -90, 31, 61, -88, 22, 67, -85, 13, 73, -82, 4, 78, -78, -4, 82, -73, -13, 85, -67, -22, 88, -61, -31, 90, -54, -38, 90, -46 },
  { 43, -90, 57, 25, -87, 70, 9, -80, 80, -9, -70, 87, -25, -57, 90, -43, -43, 90, -57, -25, 87, -70, -9, 80, -80, 9, 70, -87, 25, 57, -90, 43 },
  { 38, -88, 73, -4, -67, 90, -46, -31, 85, -78, 13, 61, -90, 54, 22, -82, 82, -22, -54, 90, -61, -13, 78, -85, 31, 46, -90, 67, 4, -73, 88, -38 },
  { 36, -83, 83, -36, -36, 83, -83, 36, 36, -83, 83, -36, -36, 83, -83, 36, 36, -83, 83, -36, -36, 83, -83, 36, 36, -83, 83, -36, -36, 83, -83, 36 },
  { 31, -78, 90, -61, 4, 54, -88, 82, -38, -22, 73, -90, 67, -13, -46, 85, -85, 46, 13, -67, 90, -73, 22, 38, -82, 88, -54, -4, 61, -90, 78, -31 },
  { 25, -70, 90, -80, 43, 9, -57, 87, -87, 57, -9, -43, 80, -90, 70, -25, -25, 70, -90, 80, -43, -9, 57, -87, 87, -57, 9, 43, -80, 90, -70, 25 },
  { 22, -61, 85, -90, 73, -38, -4, 46, -78, 90, -82, 54, -13, -31, 67, -88, 88, -67, 31, 13, -54, 82, -90, 78, -46, 4, 38, -73, 90, -85, 61, -22 },
  { 18, -50, 75, -89, 89, -75, 50, -18, -18, 50, -75, 89, -89, 75, -50, 18, 18, -50, 75, -89, 89, -75, 50, -18, -18, 50, -75, 89, -89, 75, -50, 18 },
  { 13, -38, 61, -78, 88, -90, 85, -73, 54, -31, 4, 22, -46, 67, -82, 90, -90, 82, -67, 46, -22, -4, 31, -54, 73, -85, 90, -88, 78, -61, 38, -13 },
  { 9, -25, 43, -57, 70, -80, 87, -90, 90, -87, 80, -70, 57, -43, 25, -9, -9, 25, -43, 57, -70, 80, -87, 90, -90, 87, -80, 70, -57, 43, -25, 9 },
  { 4, -13, 22, -31, 38, -46, 54, -61, 67, -73, 78, -82, 85, -88, 90, -90, 90, -90, 88, -85, 82, -78, 73, -67, 61, -54, 46, -38, 31, -22, 13, -4 }
};

ALIGNED(64) const int16_t uvg_g_dct_64[64][64] =
{
   { 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, },
   { 91, 90, 90, 90, 88, 87, 86, 84, 83, 81, 79, 77, 73, 71, 69, 65, 62, 59, 56, 52, 48, 44, 41, 37, 33, 28, 24, 20, 15, 11, 7, 2, -2, -7, -11, -15, -20, -24, -28, -33, -37, -41, -44, -48, -52, -56, -59, -62, -65, -69, -71, -73, -77, -79, -81, -83, -84, -86, -87, -88, -90, -90, -90, -91, },
   { 90, 90, 88, 85, 82, 78, 73, 67, 61, 54, 46, 38, 31, 22, 13, 4, -4, -13, -22, -31, -38, -46, -54, -61, -67, -73, -78, -82, -85, -88, -90, -90, -90, -90, -88, -85, -82, -78, -73, -67, -61, -54, -46, -38, -31, -22, -13, -4, 4, 13, 22, 31, 38, 46, 54, 61, 67, 73, 78, 82, 85, 88, 90, 90, },
   { 90, 88, 84, 79, 71, 62, 52, 41, 28, 15, 2, -11, -24, -37, -48, -59, -69, -77, -83, -87, -90, -91, -90, -86, -81, -73, -65, -56, -44, -33, -20, -7, 7, 20, 33, 44, 56, 65, 73, 81, 86, 90, 91, 90, 87, 83, 77, 69, 59, 48, 37, 24, 11, -2, -15, -28, -41, -52, -62, -71, -79, -84, -88, -90, },
   { 90, 87, 80, 70, 57, 43, 25, 9, -9, -25, -43, -57, -70, -80, -87, -90, -90, -87, -80, -70, -57, -43, -25, -9, 9, 25, 43, 57, 70, 80, 87, 90, 90, 87, 80, 70, 57, 43, 25, 9, -9, -25, -43, -57, -70, -80, -87, -90, -90, -87, -80, -70, -57, -43, -25, -9, 9, 25, 43, 57, 70, 80, 87, 90, },
   { 90, 84, 73, 59, 41, 20, -2, -24, -44, -62, -77, -86, -90, -90, -83, -71, -56, -37, -15, 7, 28, 48, 65, 79, 87, 91, 88, 81, 69, 52, 33, 11, -11, -33, -52, -69, -81, -88, -91, -87, -79, -65, -48, -28, -7, 15, 37, 56, 71, 83, 90, 90, 86, 77, 62, 44, 24, 2, -20, -41, -59, -73, -84, -90, },
   { 90, 82, 67, 46, 22, -4, -31, -54, -73, -85, -90, -88, -78, -61, -38, -13, 13, 38, 61, 78, 88, 90, 85, 73, 54, 31, 4, -22, -46, -67, -82, -90, -90, -82, -67, -46, -22, 4, 31, 54, 73, 85, 90, 88, 78, 61, 38, 13, -13, -38, -61, -78, -88, -90, -85, -73, -54, -31, -4, 22, 46, 67, 82, 90, },
   { 90, 79, 59, 33, 2, -28, -56, -77, -88, -90, -81, -62, -37, -7, 24, 52, 73, 87, 90, 83, 65, 41, 11, -20, -48, -71, -86, -91, -84, -69, -44, -15, 15, 44, 69, 84, 91, 86, 71, 48, 20, -11, -41, -65, -83, -90, -87, -73, -52, -24, 7, 37, 62, 81, 90, 88, 77, 56, 28, -2, -33, -59, -79, -90, },
   { 89, 75, 50, 18, -18, -50, -75, -89, -89, -75, -50, -18, 18, 50, 75, 89, 89, 75, 50, 18, -18, -50, -75, -89, -89, -75, -50, -18, 18, 50, 75, 89, 89, 75, 50, 18, -18, -50, -75, -89, -89, -75, -50, -18, 18, 50, 75, 89, 89, 75, 50, 18, -18, -50, -75, -89, -89, -75, -50, -18, 18, 50, 75, 89, },
   { 88, 71, 41, 2, -37, -69, -87, -90, -73, -44, -7, 33, 65, 86, 90, 77, 48, 11, -28, -62, -84, -90, -79, -52, -15, 24, 59, 83, 91, 81, 56, 20, -20, -56, -81, -91, -83, -59, -24, 15, 52, 79, 90, 84, 62, 28, -11, -48, -77, -90, -86, -65, -33, 7, 44, 73, 90, 87, 69, 37, -2, -41, -71, -88, },
   { 88, 67, 31, -13, -54, -82, -90, -78, -46, -4, 38, 73, 90, 85, 61, 22, -22, -61, -85, -90, -73, -38, 4, 46, 78, 90, 82, 54, 13, -31, -67, -88, -88, -67, -31, 13, 54, 82, 90, 78, 46, 4, -38, -73, -90, -85, -61, -22, 22, 61, 85, 90, 73, 38, -4, -46, -78, -90, -82, -54, -13, 31, 67, 88, },
   { 87, 62, 20, -28, -69, -90, -84, -56, -11, 37, 73, 90, 81, 48, 2, -44, -79, -91, -77, -41, 7, 52, 83, 90, 71, 33, -15, -59, -86, -88, -65, -24, 24, 65, 88, 86, 59, 15, -33, -71, -90, -83, -52, -7, 41, 77, 91, 79, 44, -2, -48, -81, -90, -73, -37, 11, 56, 84, 90, 69, 28, -20, -62, -87, },
   { 87, 57, 9, -43, -80, -90, -70, -25, 25, 70, 90, 80, 43, -9, -57, -87, -87, -57, -9, 43, 80, 90, 70, 25, -25, -70, -90, -80, -43, 9, 57, 87, 87, 57, 9, -43, -80, -90, -70, -25, 25, 70, 90, 80, 43, -9, -57, -87, -87, -57, -9, 43, 80, 90, 70, 25, -25, -70, -90, -80, -43, 9, 57, 87, },
   { 86, 52, -2, -56, -87, -84, -48, 7, 59, 88, 83, 44, -11, -62, -90, -81, -41, 15, 65, 90, 79, 37, -20, -69, -90, -77, -33, 24, 71, 91, 73, 28, -28, -73, -91, -71, -24, 33, 77, 90, 69, 20, -37, -79, -90, -65, -15, 41, 81, 90, 62, 11, -44, -83, -88, -59, -7, 48, 84, 87, 56, 2, -52, -86, },
   { 85, 46, -13, -67, -90, -73, -22, 38, 82, 88, 54, -4, -61, -90, -78, -31, 31, 78, 90, 61, 4, -54, -88, -82, -38, 22, 73, 90, 67, 13, -46, -85, -85, -46, 13, 67, 90, 73, 22, -38, -82, -88, -54, 4, 61, 90, 78, 31, -31, -78, -90, -61, -4, 54, 88, 82, 38, -22, -73, -90, -67, -13, 46, 85, },
   { 84, 41, -24, -77, -90, -56, 7, 65, 91, 69, 11, -52, -88, -79, -28, 37, 83, 86, 44, -20, -73, -90, -59, 2, 62, 90, 71, 15, -48, -87, -81, -33, 33, 81, 87, 48, -15, -71, -90, -62, -2, 59, 90, 73, 20, -44, -86, -83, -37, 28, 79, 88, 52, -11, -69, -91, -65, -7, 56, 90, 77, 24, -41, -84, },
   { 83, 36, -36, -83, -83, -36, 36, 83, 83, 36, -36, -83, -83, -36, 36, 83, 83, 36, -36, -83, -83, -36, 36, 83, 83, 36, -36, -83, -83, -36, 36, 83, 83, 36, -36, -83, -83, -36, 36, 83, 83, 36, -36, -83, -83, -36, 36, 83, 83, 36, -36, -83, -83, -36, 36, 83, 83, 36, -36, -83, -83, -36, 36, 83, },
   { 83, 28, -44, -88, -73, -11, 59, 91, 62, -7, -71, -90, -48, 24, 81, 84, 33, -41, -87, -77, -15, 56, 90, 65, -2, -69, -90, -52, 20, 79, 86, 37, -37, -86, -79, -20, 52, 90, 69, 2, -65, -90, -56, 15, 77, 87, 41, -33, -84, -81, -24, 48, 90, 71, 7, -62, -91, -59, 11, 73, 88, 44, -28, -83, },
   { 82, 22, -54, -90, -61, 13, 78, 85, 31, -46, -90, -67, 4, 73, 88, 38, -38, -88, -73, -4, 67, 90, 46, -31, -85, -78, -13, 61, 90, 54, -22, -82, -82, -22, 54, 90, 61, -13, -78, -85, -31, 46, 90, 67, -4, -73, -88, -38, 38, 88, 73, 4, -67, -90, -46, 31, 85, 78, 13, -61, -90, -54, 22, 82, },
   { 81, 15, -62, -90, -44, 37, 88, 69, -7, -77, -84, -24, 56, 91, 52, -28, -86, -73, -2, 71, 87, 33, -48, -90, -59, 20, 83, 79, 11, -65, -90, -41, 41, 90, 65, -11, -79, -83, -20, 59, 90, 48, -33, -87, -71, 2, 73, 86, 28, -52, -91, -56, 24, 84, 77, 7, -69, -88, -37, 44, 90, 62, -15, -81, },
   { 80, 9, -70, -87, -25, 57, 90, 43, -43, -90, -57, 25, 87, 70, -9, -80, -80, -9, 70, 87, 25, -57, -90, -43, 43, 90, 57, -25, -87, -70, 9, 80, 80, 9, -70, -87, -25, 57, 90, 43, -43, -90, -57, 25, 87, 70, -9, -80, -80, -9, 70, 87, 25, -57, -90, -43, 43, 90, 57, -25, -87, -70, 9, 80, },
   { 79, 2, -77, -81, -7, 73, 83, 11, -71, -84, -15, 69, 86, 20, -65, -87, -24, 62, 88, 28, -59, -90, -33, 56, 90, 37, -52, -90, -41, 48, 91, 44, -44, -91, -48, 41, 90, 52, -37, -90, -56, 33, 90, 59, -28, -88, -62, 24, 87, 65, -20, -86, -69, 15, 84, 71, -11, -83, -73, 7, 81, 77, -2, -79, },
   { 78, -4, -82, -73, 13, 85, 67, -22, -88, -61, 31, 90, 54, -38, -90, -46, 46, 90, 38, -54, -90, -31, 61, 88, 22, -67, -85, -13, 73, 82, 4, -78, -78, 4, 82, 73, -13, -85, -67, 22, 88, 61, -31, -90, -54, 38, 90, 46, -46, -90, -38, 54, 90, 31, -61, -88, -22, 67, 85, 13, -73, -82, -4, 78, },
   { 77, -11, -86, -62, 33, 90, 44, -52, -90, -24, 69, 83, 2, -81, -71, 20, 88, 56, -41, -91, -37, 59, 87, 15, -73, -79, 7, 84, 65, -28, -90, -48, 48, 90, 28, -65, -84, -7, 79, 73, -15, -87, -59, 37, 91, 41, -56, -88, -20, 71, 81, -2, -83, -69, 24, 90, 52, -44, -90, -33, 62, 86, 11, -77, },
   { 75, -18, -89, -50, 50, 89, 18, -75, -75, 18, 89, 50, -50, -89, -18, 75, 75, -18, -89, -50, 50, 89, 18, -75, -75, 18, 89, 50, -50, -89, -18, 75, 75, -18, -89, -50, 50, 89, 18, -75, -75, 18, 89, 50, -50, -89, -18, 75, 75, -18, -89, -50, 50, 89, 18, -75, -75, 18, 89, 50, -50, -89, -18, 75, },
   { 73, -24, -90, -37, 65, 81, -11, -88, -48, 56, 86, 2, -84, -59, 44, 90, 15, -79, -69, 33, 91, 28, -71, -77, 20, 90, 41, -62, -83, 7, 87, 52, -52, -87, -7, 83, 62, -41, -90, -20, 77, 71, -28, -91, -33, 69, 79, -15, -90, -44, 59, 84, -2, -86, -56, 48, 88, 11, -81, -65, 37, 90, 24, -73, },
   { 73, -31, -90, -22, 78, 67, -38, -90, -13, 82, 61, -46, -88, -4, 85, 54, -54, -85, 4, 88, 46, -61, -82, 13, 90, 38, -67, -78, 22, 90, 31, -73, -73, 31, 90, 22, -78, -67, 38, 90, 13, -82, -61, 46, 88, 4, -85, -54, 54, 85, -4, -88, -46, 61, 82, -13, -90, -38, 67, 78, -22, -90, -31, 73, },
   { 71, -37, -90, -7, 86, 48, -62, -79, 24, 91, 20, -81, -59, 52, 84, -11, -90, -33, 73, 69, -41, -88, -2, 87, 44, -65, -77, 28, 90, 15, -83, -56, 56, 83, -15, -90, -28, 77, 65, -44, -87, 2, 88, 41, -69, -73, 33, 90, 11, -84, -52, 59, 81, -20, -91, -24, 79, 62, -48, -86, 7, 90, 37, -71, },
   { 70, -43, -87, 9, 90, 25, -80, -57, 57, 80, -25, -90, -9, 87, 43, -70, -70, 43, 87, -9, -90, -25, 80, 57, -57, -80, 25, 90, 9, -87, -43, 70, 70, -43, -87, 9, 90, 25, -80, -57, 57, 80, -25, -90, -9, 87, 43, -70, -70, 43, 87, -9, -90, -25, 80, 57, -57, -80, 25, 90, 9, -87, -43, 70, },
   { 69, -48, -83, 24, 90, 2, -90, -28, 81, 52, -65, -71, 44, 84, -20, -90, -7, 88, 33, -79, -56, 62, 73, -41, -86, 15, 91, 11, -87, -37, 77, 59, -59, -77, 37, 87, -11, -91, -15, 86, 41, -73, -62, 56, 79, -33, -88, 7, 90, 20, -84, -44, 71, 65, -52, -81, 28, 90, -2, -90, -24, 83, 48, -69, },
   { 67, -54, -78, 38, 85, -22, -90, 4, 90, 13, -88, -31, 82, 46, -73, -61, 61, 73, -46, -82, 31, 88, -13, -90, -4, 90, 22, -85, -38, 78, 54, -67, -67, 54, 78, -38, -85, 22, 90, -4, -90, -13, 88, 31, -82, -46, 73, 61, -61, -73, 46, 82, -31, -88, 13, 90, 4, -90, -22, 85, 38, -78, -54, 67, },
   { 65, -59, -71, 52, 77, -44, -81, 37, 84, -28, -87, 20, 90, -11, -90, 2, 91, 7, -90, -15, 88, 24, -86, -33, 83, 41, -79, -48, 73, 56, -69, -62, 62, 69, -56, -73, 48, 79, -41, -83, 33, 86, -24, -88, 15, 90, -7, -91, -2, 90, 11, -90, -20, 87, 28, -84, -37, 81, 44, -77, -52, 71, 59, -65, },
   { 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, 64, -64, -64, 64, },
   { 62, -69, -56, 73, 48, -79, -41, 83, 33, -86, -24, 88, 15, -90, -7, 91, -2, -90, 11, 90, -20, -87, 28, 84, -37, -81, 44, 77, -52, -71, 59, 65, -65, -59, 71, 52, -77, -44, 81, 37, -84, -28, 87, 20, -90, -11, 90, 2, -91, 7, 90, -15, -88, 24, 86, -33, -83, 41, 79, -48, -73, 56, 69, -62, },
   { 61, -73, -46, 82, 31, -88, -13, 90, -4, -90, 22, 85, -38, -78, 54, 67, -67, -54, 78, 38, -85, -22, 90, 4, -90, 13, 88, -31, -82, 46, 73, -61, -61, 73, 46, -82, -31, 88, 13, -90, 4, 90, -22, -85, 38, 78, -54, -67, 67, 54, -78, -38, 85, 22, -90, -4, 90, -13, -88, 31, 82, -46, -73, 61, },
   { 59, -77, -37, 87, 11, -91, 15, 86, -41, -73, 62, 56, -79, -33, 88, 7, -90, 20, 84, -44, -71, 65, 52, -81, -28, 90, 2, -90, 24, 83, -48, -69, 69, 48, -83, -24, 90, -2, -90, 28, 81, -52, -65, 71, 44, -84, -20, 90, -7, -88, 33, 79, -56, -62, 73, 41, -86, -15, 91, -11, -87, 37, 77, -59, },
   { 57, -80, -25, 90, -9, -87, 43, 70, -70, -43, 87, 9, -90, 25, 80, -57, -57, 80, 25, -90, 9, 87, -43, -70, 70, 43, -87, -9, 90, -25, -80, 57, 57, -80, -25, 90, -9, -87, 43, 70, -70, -43, 87, 9, -90, 25, 80, -57, -57, 80, 25, -90, 9, 87, -43, -70, 70, 43, -87, -9, 90, -25, -80, 57, },
   { 56, -83, -15, 90, -28, -77, 65, 44, -87, -2, 88, -41, -69, 73, 33, -90, 11, 84, -52, -59, 81, 20, -91, 24, 79, -62, -48, 86, 7, -90, 37, 71, -71, -37, 90, -7, -86, 48, 62, -79, -24, 91, -20, -81, 59, 52, -84, -11, 90, -33, -73, 69, 41, -88, 2, 87, -44, -65, 77, 28, -90, 15, 83, -56, },
   { 54, -85, -4, 88, -46, -61, 82, 13, -90, 38, 67, -78, -22, 90, -31, -73, 73, 31, -90, 22, 78, -67, -38, 90, -13, -82, 61, 46, -88, 4, 85, -54, -54, 85, 4, -88, 46, 61, -82, -13, 90, -38, -67, 78, 22, -90, 31, 73, -73, -31, 90, -22, -78, 67, 38, -90, 13, 82, -61, -46, 88, -4, -85, 54, },
   { 52, -87, 7, 83, -62, -41, 90, -20, -77, 71, 28, -91, 33, 69, -79, -15, 90, -44, -59, 84, 2, -86, 56, 48, -88, 11, 81, -65, -37, 90, -24, -73, 73, 24, -90, 37, 65, -81, -11, 88, -48, -56, 86, -2, -84, 59, 44, -90, 15, 79, -69, -33, 91, -28, -71, 77, 20, -90, 41, 62, -83, -7, 87, -52, },
   { 50, -89, 18, 75, -75, -18, 89, -50, -50, 89, -18, -75, 75, 18, -89, 50, 50, -89, 18, 75, -75, -18, 89, -50, -50, 89, -18, -75, 75, 18, -89, 50, 50, -89, 18, 75, -75, -18, 89, -50, -50, 89, -18, -75, 75, 18, -89, 50, 50, -89, 18, 75, -75, -18, 89, -50, -50, 89, -18, -75, 75, 18, -89, 50, },
   { 48, -90, 28, 65, -84, 7, 79, -73, -15, 87, -59, -37, 91, -41, -56, 88, -20, -71, 81, 2, -83, 69, 24, -90, 52, 44, -90, 33, 62, -86, 11, 77, -77, -11, 86, -62, -33, 90, -44, -52, 90, -24, -69, 83, -2, -81, 71, 20, -88, 56, 41, -91, 37, 59, -87, 15, 73, -79, -7, 84, -65, -28, 90, -48, },
   { 46, -90, 38, 54, -90, 31, 61, -88, 22, 67, -85, 13, 73, -82, 4, 78, -78, -4, 82, -73, -13, 85, -67, -22, 88, -61, -31, 90, -54, -38, 90, -46, -46, 90, -38, -54, 90, -31, -61, 88, -22, -67, 85, -13, -73, 82, -4, -78, 78, 4, -82, 73, 13, -85, 67, 22, -88, 61, 31, -90, 54, 38, -90, 46, },
   { 44, -91, 48, 41, -90, 52, 37, -90, 56, 33, -90, 59, 28, -88, 62, 24, -87, 65, 20, -86, 69, 15, -84, 71, 11, -83, 73, 7, -81, 77, 2, -79, 79, -2, -77, 81, -7, -73, 83, -11, -71, 84, -15, -69, 86, -20, -65, 87, -24, -62, 88, -28, -59, 90, -33, -56, 90, -37, -52, 90, -41, -48, 91, -44, },
   { 43, -90, 57, 25, -87, 70, 9, -80, 80, -9, -70, 87, -25, -57, 90, -43, -43, 90, -57, -25, 87, -70, -9, 80, -80, 9, 70, -87, 25, 57, -90, 43, 43, -90, 57, 25, -87, 70, 9, -80, 80, -9, -70, 87, -25, -57, 90, -43, -43, 90, -57, -25, 87, -70, -9, 80, -80, 9, 70, -87, 25, 57, -90, 43, },
   { 41, -90, 65, 11, -79, 83, -20, -59, 90, -48, -33, 87, -71, -2, 73, -86, 28, 52, -91, 56, 24, -84, 77, -7, -69, 88, -37, -44, 90, -62, -15, 81, -81, 15, 62, -90, 44, 37, -88, 69, 7, -77, 84, -24, -56, 91, -52, -28, 86, -73, 2, 71, -87, 33, 48, -90, 59, 20, -83, 79, -11, -65, 90, -41, },
   { 38, -88, 73, -4, -67, 90, -46, -31, 85, -78, 13, 61, -90, 54, 22, -82, 82, -22, -54, 90, -61, -13, 78, -85, 31, 46, -90, 67, 4, -73, 88, -38, -38, 88, -73, 4, 67, -90, 46, 31, -85, 78, -13, -61, 90, -54, -22, 82, -82, 22, 54, -90, 61, 13, -78, 85, -31, -46, 90, -67, -4, 73, -88, 38, },
   { 37, -86, 79, -20, -52, 90, -69, 2, 65, -90, 56, 15, -77, 87, -41, -33, 84, -81, 24, 48, -90, 71, -7, -62, 91, -59, -11, 73, -88, 44, 28, -83, 83, -28, -44, 88, -73, 11, 59, -91, 62, 7, -71, 90, -48, -24, 81, -84, 33, 41, -87, 77, -15, -56, 90, -65, -2, 69, -90, 52, 20, -79, 86, -37, },
   { 36, -83, 83, -36, -36, 83, -83, 36, 36, -83, 83, -36, -36, 83, -83, 36, 36, -83, 83, -36, -36, 83, -83, 36, 36, -83, 83, -36, -36, 83, -83, 36, 36, -83, 83, -36, -36, 83, -83, 36, 36, -83, 83, -36, -36, 83, -83, 36, 36, -83, 83, -36, -36, 83, -83, 36, 36, -83, 83, -36, -36, 83, -83, 36, },
   { 33, -81, 87, -48, -15, 71, -90, 62, -2, -59, 90, -73, 20, 44, -86, 83, -37, -28, 79, -88, 52, 11, -69, 91, -65, 7, 56, -90, 77, -24, -41, 84, -84, 41, 24, -77, 90, -56, -7, 65, -91, 69, -11, -52, 88, -79, 28, 37, -83, 86, -44, -20, 73, -90, 59, 2, -62, 90, -71, 15, 48, -87, 81, -33, },
   { 31, -78, 90, -61, 4, 54, -88, 82, -38, -22, 73, -90, 67, -13, -46, 85, -85, 46, 13, -67, 90, -73, 22, 38, -82, 88, -54, -4, 61, -90, 78, -31, -31, 78, -90, 61, -4, -54, 88, -82, 38, 22, -73, 90, -67, 13, 46, -85, 85, -46, -13, 67, -90, 73, -22, -38, 82, -88, 54, 4, -61, 90, -78, 31, },
   { 28, -73, 91, -71, 24, 33, -77, 90, -69, 20, 37, -79, 90, -65, 15, 41, -81, 90, -62, 11, 44, -83, 88, -59, 7, 48, -84, 87, -56, 2, 52, -86, 86, -52, -2, 56, -87, 84, -48, -7, 59, -88, 83, -44, -11, 62, -90, 81, -41, -15, 65, -90, 79, -37, -20, 69, -90, 77, -33, -24, 71, -91, 73, -28, },
   { 25, -70, 90, -80, 43, 9, -57, 87, -87, 57, -9, -43, 80, -90, 70, -25, -25, 70, -90, 80, -43, -9, 57, -87, 87, -57, 9, 43, -80, 90, -70, 25, 25, -70, 90, -80, 43, 9, -57, 87, -87, 57, -9, -43, 80, -90, 70, -25, -25, 70, -90, 80, -43, -9, 57, -87, 87, -57, 9, 43, -80, 90, -70, 25, },
   { 24, -65, 88, -86, 59, -15, -33, 71, -90, 83, -52, 7, 41, -77, 91, -79, 44, 2, -48, 81, -90, 73, -37, -11, 56, -84, 90, -69, 28, 20, -62, 87, -87, 62, -20, -28, 69, -90, 84, -56, 11, 37, -73, 90, -81, 48, -2, -44, 79, -91, 77, -41, -7, 52, -83, 90, -71, 33, 15, -59, 86, -88, 65, -24, },
   { 22, -61, 85, -90, 73, -38, -4, 46, -78, 90, -82, 54, -13, -31, 67, -88, 88, -67, 31, 13, -54, 82, -90, 78, -46, 4, 38, -73, 90, -85, 61, -22, -22, 61, -85, 90, -73, 38, 4, -46, 78, -90, 82, -54, 13, 31, -67, 88, -88, 67, -31, -13, 54, -82, 90, -78, 46, -4, -38, 73, -90, 85, -61, 22, },
   { 20, -56, 81, -91, 83, -59, 24, 15, -52, 79, -90, 84, -62, 28, 11, -48, 77, -90, 86, -65, 33, 7, -44, 73, -90, 87, -69, 37, 2, -41, 71, -88, 88, -71, 41, -2, -37, 69, -87, 90, -73, 44, -7, -33, 65, -86, 90, -77, 48, -11, -28, 62, -84, 90, -79, 52, -15, -24, 59, -83, 91, -81, 56, -20, },
   { 18, -50, 75, -89, 89, -75, 50, -18, -18, 50, -75, 89, -89, 75, -50, 18, 18, -50, 75, -89, 89, -75, 50, -18, -18, 50, -75, 89, -89, 75, -50, 18, 18, -50, 75, -89, 89, -75, 50, -18, -18, 50, -75, 89, -89, 75, -50, 18, 18, -50, 75, -89, 89, -75, 50, -18, -18, 50, -75, 89, -89, 75, -50, 18, },
   { 15, -44, 69, -84, 91, -86, 71, -48, 20, 11, -41, 65, -83, 90, -87, 73, -52, 24, 7, -37, 62, -81, 90, -88, 77, -56, 28, 2, -33, 59, -79, 90, -90, 79, -59, 33, -2, -28, 56, -77, 88, -90, 81, -62, 37, -7, -24, 52, -73, 87, -90, 83, -65, 41, -11, -20, 48, -71, 86, -91, 84, -69, 44, -15, },
   { 13, -38, 61, -78, 88, -90, 85, -73, 54, -31, 4, 22, -46, 67, -82, 90, -90, 82, -67, 46, -22, -4, 31, -54, 73, -85, 90, -88, 78, -61, 38, -13, -13, 38, -61, 78, -88, 90, -85, 73, -54, 31, -4, -22, 46, -67, 82, -90, 90, -82, 67, -46, 22, 4, -31, 54, -73, 85, -90, 88, -78, 61, -38, 13, },
   { 11, -33, 52, -69, 81, -88, 91, -87, 79, -65, 48, -28, 7, 15, -37, 56, -71, 83, -90, 90, -86, 77, -62, 44, -24, 2, 20, -41, 59, -73, 84, -90, 90, -84, 73, -59, 41, -20, -2, 24, -44, 62, -77, 86, -90, 90, -83, 71, -56, 37, -15, -7, 28, -48, 65, -79, 87, -91, 88, -81, 69, -52, 33, -11, },
   { 9, -25, 43, -57, 70, -80, 87, -90, 90, -87, 80, -70, 57, -43, 25, -9, -9, 25, -43, 57, -70, 80, -87, 90, -90, 87, -80, 70, -57, 43, -25, 9, 9, -25, 43, -57, 70, -80, 87, -90, 90, -87, 80, -70, 57, -43, 25, -9, -9, 25, -43, 57, -70, 80, -87, 90, -90, 87, -80, 70, -57, 43, -25, 9, },
   { 7, -20, 33, -44, 56, -65, 73, -81, 86, -90, 91, -90, 87, -83, 77, -69, 59, -48, 37, -24, 11, 2, -15, 28, -41, 52, -62, 71, -79, 84, -88, 90, -90, 88, -84, 79, -71, 62, -52, 41, -28, 15, -2, -11, 24, -37, 48, -59, 69, -77, 83, -87, 90, -91, 90, -86, 81, -73, 65, -56, 44, -33, 20, -7, },
   { 4, -13, 22, -31, 38, -46, 54, -61, 67, -73, 78, -82, 85, -88, 90, -90, 90, -90, 88, -85, 82, -78, 73, -67, 61, -54, 46, -38, 31, -22, 13, -4, -4, 13, -22, 31, -38, 46, -54, 61, -67, 73, -78, 82, -85, 88, -90, 90, -90, 90, -88, 85, -82, 78, -73, 67, -61, 54, -46, 38, -31, 22, -13, 4, },
   { 2, -7, 11, -15, 20, -24, 28, -33, 37, -41, 44, -48, 52, -56, 59, -62, 65, -69, 71, -73, 77, -79, 81, -83, 84, -86, 87, -88, 90, -90, 90, -91, 91, -90, 90, -90, 88, -87, 86, -84, 83, -81, 79, -77, 73, -71, 69, -65, 62, -59, 56, -52, 48, -44, 41, -37, 33, -28, 24, -20, 15, -11, 7, -2, },
};

ALIGNED(64) const int16_t uvg_g_dst_4_t[4][4] =
{
  { 29, 74, 84, 55 },
  { 55, 74, -29, -84 },
  { 74, 0, -74, 74 },
  { 84, -74, 55, -29 }
};

ALIGNED(32) const int16_t uvg_g_dct_4_t[4][4] =
{
  { 64, 83, 64, 36, },
  { 64, 36, -64, -83, },
  { 64, -36, -64, 83, },
  { 64, -83, 64, -36 }
};

ALIGNED(64) const int16_t uvg_g_dct_8_t[8][8] =
{
  { 64, 89, 83, 75, 64, 50, 36, 18, },
  { 64, 75, 36, -18, -64, -89, -83, -50, },
  { 64, 50, -36, -89, -64, 18, 83, 75, },
  { 64, 18, -83, -50, 64, 75, -36, -89, },
  { 64, -18, -83, 50, 64, -75, -36, 89, },
  { 64, -50, -36, 89, -64, -18, 83, -75, },
  { 64, -75, 36, 18, -64, 89, -83, 50, },
  { 64, -89, 83, -75, 64, -50, 36, -18 }
};

ALIGNED(64) const int16_t uvg_g_dct_16_t[16][16] =
{
  { 64, 90, 89, 87, 83, 80, 75, 70, 64, 57, 50, 43, 36, 25, 18, 9, },
  { 64, 87, 75, 57, 36, 9, -18, -43, -64, -80, -89, -90, -83, -70, -50, -25, },
  { 64, 80, 50, 9, -36, -70, -89, -87, -64, -25, 18, 57, 83, 90, 75, 43, },
  { 64, 70, 18, -43, -83, -87, -50, 9, 64, 90, 75, 25, -36, -80, -89, -57, },
  { 64, 57, -18, -80, -83, -25, 50, 90, 64, -9, -75, -87, -36, 43, 89, 70, },
  { 64, 43, -50, -90, -36, 57, 89, 25, -64, -87, -18, 70, 83, 9, -75, -80, },
  { 64, 25, -75, -70, 36, 90, 18, -80, -64, 43, 89, 9, -83, -57, 50, 87, },
  { 64, 9, -89, -25, 83, 43, -75, -57, 64, 70, -50, -80, 36, 87, -18, -90, },
  { 64, -9, -89, 25, 83, -43, -75, 57, 64, -70, -50, 80, 36, -87, -18, 90, },
  { 64, -25, -75, 70, 36, -90, 18, 80, -64, -43, 89, -9, -83, 57, 50, -87, },
  { 64, -43, -50, 90, -36, -57, 89, -25, -64, 87, -18, -70, 83, -9, -75, 80, },
  { 64, -57, -18, 80, -83, 25, 50, -90, 64, 9, -75, 87, -36, -43, 89, -70, },
  { 64, -70, 18, 43, -83, 87, -50, -9, 64, -90, 75, -25, -36, 80, -89, 57, },
  { 64, -80, 50, -9, -36, 70, -89, 87, -64, 25, 18, -57, 83, -90, 75, -43, },
  { 64, -87, 75, -57, 36, -9, -18, 43, -64, 80, -89, 90, -83, 70, -50, 25, },
  { 64, -90, 89, -87, 83, -80, 75, -70, 64, -57, 50, -43, 36, -25, 18, -9 }
};

ALIGNED(64) const int16_t uvg_g_dct_32_t[32][32] =
{
  { 64, 90, 90, 90, 89, 88, 87, 85, 83, 82, 80, 78, 75, 73, 70, 67, 64, 61, 57, 54, 50, 46, 43, 38, 36, 31, 25, 22, 18, 13, 9, 4, },
  { 64, 90, 87, 82, 75, 67, 57, 46, 36, 22, 9, -4, -18, -31, -43, -54, -64, -73, -80, -85, -89, -90, -90, -88, -83, -78, -70, -61, -50, -38, -25, -13, },
  { 64, 88, 80, 67, 50, 31, 9, -13, -36, -54, -70, -82, -89, -90, -87, -78, -64, -46, -25, -4, 18, 38, 57, 73, 83, 90, 90, 85, 75, 61, 43, 22, },
  { 64, 85, 70, 46, 18, -13, -43, -67, -83, -90, -87, -73, -50, -22, 9, 38, 64, 82, 90, 88, 75, 54, 25, -4, -36, -61, -80, -90, -89, -78, -57, -31, },
  { 64, 82, 57, 22, -18, -54, -80, -90, -83, -61, -25, 13, 50, 78, 90, 85, 64, 31, -9, -46, -75, -90, -87, -67, -36, 4, 43, 73, 89, 88, 70, 38, },
  { 64, 78, 43, -4, -50, -82, -90, -73, -36, 13, 57, 85, 89, 67, 25, -22, -64, -88, -87, -61, -18, 31, 70, 90, 83, 54, 9, -38, -75, -90, -80, -46, },
  { 64, 73, 25, -31, -75, -90, -70, -22, 36, 78, 90, 67, 18, -38, -80, -90, -64, -13, 43, 82, 89, 61, 9, -46, -83, -88, -57, -4, 50, 85, 87, 54, },
  { 64, 67, 9, -54, -89, -78, -25, 38, 83, 85, 43, -22, -75, -90, -57, 4, 64, 90, 70, 13, -50, -88, -80, -31, 36, 82, 87, 46, -18, -73, -90, -61, },
  { 64, 61, -9, -73, -89, -46, 25, 82, 83, 31, -43, -88, -75, -13, 57, 90, 64, -4, -70, -90, -50, 22, 80, 85, 36, -38, -87, -78, -18, 54, 90, 67, },
  { 64, 54, -25, -85, -75, -4, 70, 88, 36, -46, -90, -61, 18, 82, 80, 13, -64, -90, -43, 38, 89, 67, -9, -78, -83, -22, 57, 90, 50, -31, -87, -73, },
  { 64, 46, -43, -90, -50, 38, 90, 54, -36, -90, -57, 31, 89, 61, -25, -88, -64, 22, 87, 67, -18, -85, -70, 13, 83, 73, -9, -82, -75, 4, 80, 78, },
  { 64, 38, -57, -88, -18, 73, 80, -4, -83, -67, 25, 90, 50, -46, -90, -31, 64, 85, 9, -78, -75, 13, 87, 61, -36, -90, -43, 54, 89, 22, -70, -82, },
  { 64, 31, -70, -78, 18, 90, 43, -61, -83, 4, 87, 54, -50, -88, -9, 82, 64, -38, -90, -22, 75, 73, -25, -90, -36, 67, 80, -13, -89, -46, 57, 85, },
  { 64, 22, -80, -61, 50, 85, -9, -90, -36, 73, 70, -38, -89, -4, 87, 46, -64, -78, 25, 90, 18, -82, -57, 54, 83, -13, -90, -31, 75, 67, -43, -88, },
  { 64, 13, -87, -38, 75, 61, -57, -78, 36, 88, -9, -90, -18, 85, 43, -73, -64, 54, 80, -31, -89, 4, 90, 22, -83, -46, 70, 67, -50, -82, 25, 90, },
  { 64, 4, -90, -13, 89, 22, -87, -31, 83, 38, -80, -46, 75, 54, -70, -61, 64, 67, -57, -73, 50, 78, -43, -82, 36, 85, -25, -88, 18, 90, -9, -90, },
  { 64, -4, -90, 13, 89, -22, -87, 31, 83, -38, -80, 46, 75, -54, -70, 61, 64, -67, -57, 73, 50, -78, -43, 82, 36, -85, -25, 88, 18, -90, -9, 90, },
  { 64, -13, -87, 38, 75, -61, -57, 78, 36, -88, -9, 90, -18, -85, 43, 73, -64, -54, 80, 31, -89, -4, 90, -22, -83, 46, 70, -67, -50, 82, 25, -90, },
  { 64, -22, -80, 61, 50, -85, -9, 90, -36, -73, 70, 38, -89, 4, 87, -46, -64, 78, 25, -90, 18, 82, -57, -54, 83, 13, -90, 31, 75, -67, -43, 88, },
  { 64, -31, -70, 78, 18, -90, 43, 61, -83, -4, 87, -54, -50, 88, -9, -82, 64, 38, -90, 22, 75, -73, -25, 90, -36, -67, 80, 13, -89, 46, 57, -85, },
  { 64, -38, -57, 88, -18, -73, 80, 4, -83, 67, 25, -90, 50, 46, -90, 31, 64, -85, 9, 78, -75, -13, 87, -61, -36, 90, -43, -54, 89, -22, -70, 82, },
  { 64, -46, -43, 90, -50, -38, 90, -54, -36, 90, -57, -31, 89, -61, -25, 88, -64, -22, 87, -67, -18, 85, -70, -13, 83, -73, -9, 82, -75, -4, 80, -78, },
  { 64, -54, -25, 85, -75, 4, 70, -88, 36, 46, -90, 61, 18, -82, 80, -13, -64, 90, -43, -38, 89, -67, -9, 78, -83, 22, 57, -90, 50, 31, -87, 73, },
  { 64, -61, -9, 73, -89, 46, 25, -82, 83, -31, -43, 88, -75, 13, 57, -90, 64, 4, -70, 90, -50, -22, 80, -85, 36, 38, -87, 78, -18, -54, 90, -67, },
  { 64, -67, 9, 54, -89, 78, -25, -38, 83, -85, 43, 22, -75, 90, -57, -4, 64, -90, 70, -13, -50, 88, -80, 31, 36, -82, 87, -46, -18, 73, -90, 61, },
  { 64, -73, 25, 31, -75, 90, -70, 22, 36, -78, 90, -67, 18, 38, -80, 90, -64, 13, 43, -82, 89, -61, 9, 46, -83, 88, -57, 4, 50, -85, 87, -54, },
  { 64, -78, 43, 4, -50, 82, -90, 73, -36, -13, 57, -85, 89, -67, 25, 22, -64, 88, -87, 61, -18, -31, 70, -90, 83, -54, 9, 38, -75, 90, -80, 46, },
  { 64, -82, 57, -22, -18, 54, -80, 90, -83, 61, -25, -13, 50, -78, 90, -85, 64, -31, -9, 46, -75, 90, -87, 67, -36, -4, 43, -73, 89, -88, 70, -38, },
  { 64, -85, 70, -46, 18, 13, -43, 67, -83, 90, -87, 73, -50, 22, 9, -38, 64, -82, 90, -88, 75, -54, 25, 4, -36, 61, -80, 90, -89, 78, -57, 31, },
  { 64, -88, 80, -67, 50, -31, 9, 13, -36, 54, -70, 82, -89, 90, -87, 78, -64, 46, -25, 4, 18, -38, 57, -73, 83, -90, 90, -85, 75, -61, 43, -22, },
  { 64, -90, 87, -82, 75, -67, 57, -46, 36, -22, 9, 4, -18, 31, -43, 54, -64, 73, -80, 85, -89, 90, -90, 88, -83, 78, -70, 61, -50, 38, -25, 13, },
  { 64, -90, 90, -90, 89, -88, 87, -85, 83, -82, 80, -78, 75, -73, 70, -67, 64, -61, 57, -54, 50, -46, 43, -38, 36, -31, 25, -22, 18, -13, 9, -4 }
};

const int16_t uvg_g_dct_64_t[64][64] =
{
  { 64, 91, 90, 90, 90, 90, 90, 90, 89, 88, 88, 87, 87, 86, 85, 84, 83, 83, 82, 81, 80, 79, 78, 77, 75, 73, 73, 71, 70, 69, 67, 65, 64, 62, 61, 59, 57, 56, 54, 52, 50, 48, 46, 44, 43, 41, 38, 37, 36, 33, 31, 28, 25, 24, 22, 20, 18, 15, 13, 11, 9, 7, 4, 2, },
  { 64, 90, 90, 88, 87, 84, 82, 79, 75, 71, 67, 62, 57, 52, 46, 41, 36, 28, 22, 15, 9, 2, -4, -11, -18, -24, -31, -37, -43, -48, -54, -59, -64, -69, -73, -77, -80, -83, -85, -87, -89, -90, -90, -91, -90, -90, -88, -86, -83, -81, -78, -73, -70, -65, -61, -56, -50, -44, -38, -33, -25, -20, -13, -7, },
  { 64, 90, 88, 84, 80, 73, 67, 59, 50, 41, 31, 20, 9, -2, -13, -24, -36, -44, -54, -62, -70, -77, -82, -86, -89, -90, -90, -90, -87, -83, -78, -71, -64, -56, -46, -37, -25, -15, -4, 7, 18, 28, 38, 48, 57, 65, 73, 79, 83, 87, 90, 91, 90, 88, 85, 81, 75, 69, 61, 52, 43, 33, 22, 11, },
  { 64, 90, 85, 79, 70, 59, 46, 33, 18, 2, -13, -28, -43, -56, -67, -77, -83, -88, -90, -90, -87, -81, -73, -62, -50, -37, -22, -7, 9, 24, 38, 52, 64, 73, 82, 87, 90, 90, 88, 83, 75, 65, 54, 41, 25, 11, -4, -20, -36, -48, -61, -71, -80, -86, -90, -91, -89, -84, -78, -69, -57, -44, -31, -15, },
  { 64, 88, 82, 71, 57, 41, 22, 2, -18, -37, -54, -69, -80, -87, -90, -90, -83, -73, -61, -44, -25, -7, 13, 33, 50, 65, 78, 86, 90, 90, 85, 77, 64, 48, 31, 11, -9, -28, -46, -62, -75, -84, -90, -90, -87, -79, -67, -52, -36, -15, 4, 24, 43, 59, 73, 83, 89, 91, 88, 81, 70, 56, 38, 20, },
  { 64, 87, 78, 62, 43, 20, -4, -28, -50, -69, -82, -90, -90, -84, -73, -56, -36, -11, 13, 37, 57, 73, 85, 90, 89, 81, 67, 48, 25, 2, -22, -44, -64, -79, -88, -91, -87, -77, -61, -41, -18, 7, 31, 52, 70, 83, 90, 90, 83, 71, 54, 33, 9, -15, -38, -59, -75, -86, -90, -88, -80, -65, -46, -24, },
  { 64, 86, 73, 52, 25, -2, -31, -56, -75, -87, -90, -84, -70, -48, -22, 7, 36, 59, 78, 88, 90, 83, 67, 44, 18, -11, -38, -62, -80, -90, -90, -81, -64, -41, -13, 15, 43, 65, 82, 90, 89, 79, 61, 37, 9, -20, -46, -69, -83, -90, -88, -77, -57, -33, -4, 24, 50, 71, 85, 91, 87, 73, 54, 28, },
  { 64, 84, 67, 41, 9, -24, -54, -77, -89, -90, -78, -56, -25, 7, 38, 65, 83, 91, 85, 69, 43, 11, -22, -52, -75, -88, -90, -79, -57, -28, 4, 37, 64, 83, 90, 86, 70, 44, 13, -20, -50, -73, -88, -90, -80, -59, -31, 2, 36, 62, 82, 90, 87, 71, 46, 15, -18, -48, -73, -87, -90, -81, -61, -33, },
  { 64, 83, 61, 28, -9, -44, -73, -88, -89, -73, -46, -11, 25, 59, 82, 91, 83, 62, 31, -7, -43, -71, -88, -90, -75, -48, -13, 24, 57, 81, 90, 84, 64, 33, -4, -41, -70, -87, -90, -77, -50, -15, 22, 56, 80, 90, 85, 65, 36, -2, -38, -69, -87, -90, -78, -52, -18, 20, 54, 79, 90, 86, 67, 37, },
  { 64, 81, 54, 15, -25, -62, -85, -90, -75, -44, -4, 37, 70, 88, 88, 69, 36, -7, -46, -77, -90, -84, -61, -24, 18, 56, 82, 91, 80, 52, 13, -28, -64, -86, -90, -73, -43, -2, 38, 71, 89, 87, 67, 33, -9, -48, -78, -90, -83, -59, -22, 20, 57, 83, 90, 79, 50, 11, -31, -65, -87, -90, -73, -41, },
  { 64, 79, 46, 2, -43, -77, -90, -81, -50, -7, 38, 73, 90, 83, 54, 11, -36, -71, -90, -84, -57, -15, 31, 69, 89, 86, 61, 20, -25, -65, -88, -87, -64, -24, 22, 62, 87, 88, 67, 28, -18, -59, -85, -90, -70, -33, 13, 56, 83, 90, 73, 37, -9, -52, -82, -90, -75, -41, 4, 48, 80, 91, 78, 44, },
  { 64, 77, 38, -11, -57, -86, -88, -62, -18, 33, 73, 90, 80, 44, -4, -52, -83, -90, -67, -24, 25, 69, 90, 83, 50, 2, -46, -81, -90, -71, -31, 20, 64, 88, 85, 56, 9, -41, -78, -91, -75, -37, 13, 59, 87, 87, 61, 15, -36, -73, -90, -79, -43, 7, 54, 84, 89, 65, 22, -28, -70, -90, -82, -48, },
  { 64, 73, 31, -24, -70, -90, -78, -37, 18, 65, 90, 81, 43, -11, -61, -88, -83, -48, 4, 56, 87, 86, 54, 2, -50, -84, -88, -59, -9, 44, 82, 90, 64, 15, -38, -79, -90, -69, -22, 33, 75, 91, 73, 28, -25, -71, -90, -77, -36, 20, 67, 90, 80, 41, -13, -62, -89, -83, -46, 7, 57, 87, 85, 52, },
  { 64, 71, 22, -37, -80, -90, -61, -7, 50, 86, 85, 48, -9, -62, -90, -79, -36, 24, 73, 91, 70, 20, -38, -81, -89, -59, -4, 52, 87, 84, 46, -11, -64, -90, -78, -33, 25, 73, 90, 69, 18, -41, -82, -88, -57, -2, 54, 87, 83, 44, -13, -65, -90, -77, -31, 28, 75, 90, 67, 15, -43, -83, -88, -56, },
  { 64, 69, 13, -48, -87, -83, -38, 24, 75, 90, 61, 2, -57, -90, -78, -28, 36, 81, 88, 52, -9, -65, -90, -71, -18, 44, 85, 84, 43, -20, -73, -90, -64, -7, 54, 88, 80, 33, -31, -79, -89, -56, 4, 62, 90, 73, 22, -41, -83, -86, -46, 15, 70, 91, 67, 11, -50, -87, -82, -37, 25, 77, 90, 59, },
  { 64, 65, 4, -59, -90, -71, -13, 52, 89, 77, 22, -44, -87, -81, -31, 37, 83, 84, 38, -28, -80, -87, -46, 20, 75, 90, 54, -11, -70, -90, -61, 2, 64, 91, 67, 7, -57, -90, -73, -15, 50, 88, 78, 24, -43, -86, -82, -33, 36, 83, 85, 41, -25, -79, -88, -48, 18, 73, 90, 56, -9, -69, -90, -62, },
  { 64, 62, -4, -69, -90, -56, 13, 73, 89, 48, -22, -79, -87, -41, 31, 83, 83, 33, -38, -86, -80, -24, 46, 88, 75, 15, -54, -90, -70, -7, 61, 91, 64, -2, -67, -90, -57, 11, 73, 90, 50, -20, -78, -87, -43, 28, 82, 84, 36, -37, -85, -81, -25, 44, 88, 77, 18, -52, -90, -71, -9, 59, 90, 65, },
  { 64, 59, -13, -77, -87, -37, 38, 87, 75, 11, -61, -91, -57, 15, 78, 86, 36, -41, -88, -73, -9, 62, 90, 56, -18, -79, -85, -33, 43, 88, 73, 7, -64, -90, -54, 20, 80, 84, 31, -44, -89, -71, -4, 65, 90, 52, -22, -81, -83, -28, 46, 90, 70, 2, -67, -90, -50, 24, 82, 83, 25, -48, -90, -69, },
  { 64, 56, -22, -83, -80, -15, 61, 90, 50, -28, -85, -77, -9, 65, 90, 44, -36, -87, -73, -2, 70, 88, 38, -41, -89, -69, 4, 73, 87, 33, -46, -90, -64, 11, 78, 84, 25, -52, -90, -59, 18, 81, 82, 20, -57, -91, -54, 24, 83, 79, 13, -62, -90, -48, 31, 86, 75, 7, -67, -90, -43, 37, 88, 71, },
  { 64, 52, -31, -87, -70, 7, 78, 83, 18, -62, -90, -41, 43, 90, 61, -20, -83, -77, -4, 71, 87, 28, -54, -91, -50, 33, 88, 69, -9, -79, -82, -15, 64, 90, 38, -44, -90, -59, 22, 84, 75, 2, -73, -86, -25, 56, 90, 48, -36, -88, -67, 11, 80, 81, 13, -65, -89, -37, 46, 90, 57, -24, -85, -73, },
  { 64, 48, -38, -90, -57, 28, 88, 65, -18, -84, -73, 7, 80, 79, 4, -73, -83, -15, 67, 87, 25, -59, -90, -37, 50, 91, 46, -41, -90, -56, 31, 88, 64, -20, -85, -71, 9, 81, 78, 2, -75, -83, -13, 69, 87, 24, -61, -90, -36, 52, 90, 44, -43, -90, -54, 33, 89, 62, -22, -86, -70, 11, 82, 77, },
  { 64, 44, -46, -91, -43, 48, 90, 41, -50, -90, -38, 52, 90, 37, -54, -90, -36, 56, 90, 33, -57, -90, -31, 59, 89, 28, -61, -88, -25, 62, 88, 24, -64, -87, -22, 65, 87, 20, -67, -86, -18, 69, 85, 15, -70, -84, -13, 71, 83, 11, -73, -83, -9, 73, 82, 7, -75, -81, -4, 77, 80, 2, -78, -79, },
  { 64, 41, -54, -90, -25, 65, 85, 11, -75, -79, 4, 83, 70, -20, -88, -59, 36, 90, 46, -48, -90, -33, 61, 87, 18, -71, -82, -2, 80, 73, -13, -86, -64, 28, 90, 52, -43, -91, -38, 56, 89, 24, -67, -84, -9, 77, 78, -7, -83, -69, 22, 88, 57, -37, -90, -44, 50, 90, 31, -62, -87, -15, 73, 81, },
  { 64, 37, -61, -86, -9, 79, 73, -20, -89, -52, 46, 90, 25, -69, -82, 2, 83, 65, -31, -90, -43, 56, 88, 15, -75, -77, 13, 87, 57, -41, -90, -33, 64, 84, 4, -81, -70, 24, 90, 48, -50, -90, -22, 71, 80, -7, -85, -62, 36, 91, 38, -59, -87, -11, 78, 73, -18, -88, -54, 44, 90, 28, -67, -83, },
  { 64, 33, -67, -81, 9, 87, 54, -48, -89, -15, 78, 71, -25, -90, -38, 62, 83, -2, -85, -59, 43, 90, 22, -73, -75, 20, 90, 44, -57, -86, -4, 83, 64, -37, -90, -28, 70, 79, -13, -88, -50, 52, 88, 11, -80, -69, 31, 91, 36, -65, -82, 7, 87, 56, -46, -90, -18, 77, 73, -24, -90, -41, 61, 84, },
  { 64, 28, -73, -73, 25, 91, 31, -71, -75, 24, 90, 33, -70, -77, 22, 90, 36, -69, -78, 20, 90, 37, -67, -79, 18, 90, 38, -65, -80, 15, 90, 41, -64, -81, 13, 90, 43, -62, -82, 11, 89, 44, -61, -83, 9, 88, 46, -59, -83, 7, 88, 48, -57, -84, 4, 87, 50, -56, -85, 2, 87, 52, -54, -86, },
  { 64, 24, -78, -65, 43, 88, 4, -86, -50, 59, 82, -15, -90, -33, 73, 71, -36, -90, -13, 83, 57, -52, -85, 7, 89, 41, -67, -77, 25, 91, 22, -79, -64, 44, 88, 2, -87, -48, 61, 81, -18, -90, -31, 73, 70, -37, -90, -11, 83, 56, -54, -84, 9, 90, 38, -69, -75, 28, 90, 20, -80, -62, 46, 87, },
  { 64, 20, -82, -56, 57, 81, -22, -91, -18, 83, 54, -59, -80, 24, 90, 15, -83, -52, 61, 79, -25, -90, -13, 84, 50, -62, -78, 28, 90, 11, -85, -48, 64, 77, -31, -90, -9, 86, 46, -65, -75, 33, 90, 7, -87, -44, 67, 73, -36, -90, -4, 87, 43, -69, -73, 37, 89, 2, -88, -41, 70, 71, -38, -88, },
  { 64, 15, -85, -44, 70, 69, -46, -84, 18, 91, 13, -86, -43, 71, 67, -48, -83, 20, 90, 11, -87, -41, 73, 65, -50, -83, 22, 90, 9, -87, -38, 73, 64, -52, -82, 24, 90, 7, -88, -37, 75, 62, -54, -81, 25, 90, 4, -88, -36, 77, 61, -56, -80, 28, 90, 2, -89, -33, 78, 59, -57, -79, 31, 90, },
  { 64, 11, -88, -33, 80, 52, -67, -69, 50, 81, -31, -88, 9, 91, 13, -87, -36, 79, 54, -65, -70, 48, 82, -28, -89, 7, 90, 15, -87, -37, 78, 56, -64, -71, 46, 83, -25, -90, 4, 90, 18, -86, -38, 77, 57, -62, -73, 44, 83, -24, -90, 2, 90, 20, -85, -41, 75, 59, -61, -73, 43, 84, -22, -90, },
  { 64, 7, -90, -20, 87, 33, -82, -44, 75, 56, -67, -65, 57, 73, -46, -81, 36, 86, -22, -90, 9, 91, 4, -90, -18, 87, 31, -83, -43, 77, 54, -69, -64, 59, 73, -48, -80, 37, 85, -24, -89, 11, 90, 2, -90, -15, 88, 28, -83, -41, 78, 52, -70, -62, 61, 71, -50, -79, 38, 84, -25, -88, 13, 90, },
  { 64, 2, -90, -7, 90, 11, -90, -15, 89, 20, -88, -24, 87, 28, -85, -33, 83, 37, -82, -41, 80, 44, -78, -48, 75, 52, -73, -56, 70, 59, -67, -62, 64, 65, -61, -69, 57, 71, -54, -73, 50, 77, -46, -79, 43, 81, -38, -83, 36, 84, -31, -86, 25, 87, -22, -88, 18, 90, -13, -90, 9, 90, -4, -91, },
  { 64, -2, -90, 7, 90, -11, -90, 15, 89, -20, -88, 24, 87, -28, -85, 33, 83, -37, -82, 41, 80, -44, -78, 48, 75, -52, -73, 56, 70, -59, -67, 62, 64, -65, -61, 69, 57, -71, -54, 73, 50, -77, -46, 79, 43, -81, -38, 83, 36, -84, -31, 86, 25, -87, -22, 88, 18, -90, -13, 90, 9, -90, -4, 91, },
  { 64, -7, -90, 20, 87, -33, -82, 44, 75, -56, -67, 65, 57, -73, -46, 81, 36, -86, -22, 90, 9, -91, 4, 90, -18, -87, 31, 83, -43, -77, 54, 69, -64, -59, 73, 48, -80, -37, 85, 24, -89, -11, 90, -2, -90, 15, 88, -28, -83, 41, 78, -52, -70, 62, 61, -71, -50, 79, 38, -84, -25, 88, 13, -90, },
  { 64, -11, -88, 33, 80, -52, -67, 69, 50, -81, -31, 88, 9, -91, 13, 87, -36, -79, 54, 65, -70, -48, 82, 28, -89, -7, 90, -15, -87, 37, 78, -56, -64, 71, 46, -83, -25, 90, 4, -90, 18, 86, -38, -77, 57, 62, -73, -44, 83, 24, -90, -2, 90, -20, -85, 41, 75, -59, -61, 73, 43, -84, -22, 90, },
  { 64, -15, -85, 44, 70, -69, -46, 84, 18, -91, 13, 86, -43, -71, 67, 48, -83, -20, 90, -11, -87, 41, 73, -65, -50, 83, 22, -90, 9, 87, -38, -73, 64, 52, -82, -24, 90, -7, -88, 37, 75, -62, -54, 81, 25, -90, 4, 88, -36, -77, 61, 56, -80, -28, 90, -2, -89, 33, 78, -59, -57, 79, 31, -90, },
  { 64, -20, -82, 56, 57, -81, -22, 91, -18, -83, 54, 59, -80, -24, 90, -15, -83, 52, 61, -79, -25, 90, -13, -84, 50, 62, -78, -28, 90, -11, -85, 48, 64, -77, -31, 90, -9, -86, 46, 65, -75, -33, 90, -7, -87, 44, 67, -73, -36, 90, -4, -87, 43, 69, -73, -37, 89, -2, -88, 41, 70, -71, -38, 88, },
  { 64, -24, -78, 65, 43, -88, 4, 86, -50, -59, 82, 15, -90, 33, 73, -71, -36, 90, -13, -83, 57, 52, -85, -7, 89, -41, -67, 77, 25, -91, 22, 79, -64, -44, 88, -2, -87, 48, 61, -81, -18, 90, -31, -73, 70, 37, -90, 11, 83, -56, -54, 84, 9, -90, 38, 69, -75, -28, 90, -20, -80, 62, 46, -87, },
  { 64, -28, -73, 73, 25, -91, 31, 71, -75, -24, 90, -33, -70, 77, 22, -90, 36, 69, -78, -20, 90, -37, -67, 79, 18, -90, 38, 65, -80, -15, 90, -41, -64, 81, 13, -90, 43, 62, -82, -11, 89, -44, -61, 83, 9, -88, 46, 59, -83, -7, 88, -48, -57, 84, 4, -87, 50, 56, -85, -2, 87, -52, -54, 86, },
  { 64, -33, -67, 81, 9, -87, 54, 48, -89, 15, 78, -71, -25, 90, -38, -62, 83, 2, -85, 59, 43, -90, 22, 73, -75, -20, 90, -44, -57, 86, -4, -83, 64, 37, -90, 28, 70, -79, -13, 88, -50, -52, 88, -11, -80, 69, 31, -91, 36, 65, -82, -7, 87, -56, -46, 90, -18, -77, 73, 24, -90, 41, 61, -84, },
  { 64, -37, -61, 86, -9, -79, 73, 20, -89, 52, 46, -90, 25, 69, -82, -2, 83, -65, -31, 90, -43, -56, 88, -15, -75, 77, 13, -87, 57, 41, -90, 33, 64, -84, 4, 81, -70, -24, 90, -48, -50, 90, -22, -71, 80, 7, -85, 62, 36, -91, 38, 59, -87, 11, 78, -73, -18, 88, -54, -44, 90, -28, -67, 83, },
  { 64, -41, -54, 90, -25, -65, 85, -11, -75, 79, 4, -83, 70, 20, -88, 59, 36, -90, 46, 48, -90, 33, 61, -87, 18, 71, -82, 2, 80, -73, -13, 86, -64, -28, 90, -52, -43, 91, -38, -56, 89, -24, -67, 84, -9, -77, 78, 7, -83, 69, 22, -88, 57, 37, -90, 44, 50, -90, 31, 62, -87, 15, 73, -81, },
  { 64, -44, -46, 91, -43, -48, 90, -41, -50, 90, -38, -52, 90, -37, -54, 90, -36, -56, 90, -33, -57, 90, -31, -59, 89, -28, -61, 88, -25, -62, 88, -24, -64, 87, -22, -65, 87, -20, -67, 86, -18, -69, 85, -15, -70, 84, -13, -71, 83, -11, -73, 83, -9, -73, 82, -7, -75, 81, -4, -77, 80, -2, -78, 79, },
  { 64, -48, -38, 90, -57, -28, 88, -65, -18, 84, -73, -7, 80, -79, 4, 73, -83, 15, 67, -87, 25, 59, -90, 37, 50, -91, 46, 41, -90, 56, 31, -88, 64, 20, -85, 71, 9, -81, 78, -2, -75, 83, -13, -69, 87, -24, -61, 90, -36, -52, 90, -44, -43, 90, -54, -33, 89, -62, -22, 86, -70, -11, 82, -77, },
  { 64, -52, -31, 87, -70, -7, 78, -83, 18, 62, -90, 41, 43, -90, 61, 20, -83, 77, -4, -71, 87, -28, -54, 91, -50, -33, 88, -69, -9, 79, -82, 15, 64, -90, 38, 44, -90, 59, 22, -84, 75, -2, -73, 86, -25, -56, 90, -48, -36, 88, -67, -11, 80, -81, 13, 65, -89, 37, 46, -90, 57, 24, -85, 73, },
  { 64, -56, -22, 83, -80, 15, 61, -90, 50, 28, -85, 77, -9, -65, 90, -44, -36, 87, -73, 2, 70, -88, 38, 41, -89, 69, 4, -73, 87, -33, -46, 90, -64, -11, 78, -84, 25, 52, -90, 59, 18, -81, 82, -20, -57, 91, -54, -24, 83, -79, 13, 62, -90, 48, 31, -86, 75, -7, -67, 90, -43, -37, 88, -71, },
  { 64, -59, -13, 77, -87, 37, 38, -87, 75, -11, -61, 91, -57, -15, 78, -86, 36, 41, -88, 73, -9, -62, 90, -56, -18, 79, -85, 33, 43, -88, 73, -7, -64, 90, -54, -20, 80, -84, 31, 44, -89, 71, -4, -65, 90, -52, -22, 81, -83, 28, 46, -90, 70, -2, -67, 90, -50, -24, 82, -83, 25, 48, -90, 69, },
  { 64, -62, -4, 69, -90, 56, 13, -73, 89, -48, -22, 79, -87, 41, 31, -83, 83, -33, -38, 86, -80, 24, 46, -88, 75, -15, -54, 90, -70, 7, 61, -91, 64, 2, -67, 90, -57, -11, 73, -90, 50, 20, -78, 87, -43, -28, 82, -84, 36, 37, -85, 81, -25, -44, 88, -77, 18, 52, -90, 71, -9, -59, 90, -65, },
  { 64, -65, 4, 59, -90, 71, -13, -52, 89, -77, 22, 44, -87, 81, -31, -37, 83, -84, 38, 28, -80, 87, -46, -20, 75, -90, 54, 11, -70, 90, -61, -2, 64, -91, 67, -7, -57, 90, -73, 15, 50, -88, 78, -24, -43, 86, -82, 33, 36, -83, 85, -41, -25, 79, -88, 48, 18, -73, 90, -56, -9, 69, -90, 62, },
  { 64, -69, 13, 48, -87, 83, -38, -24, 75, -90, 61, -2, -57, 90, -78, 28, 36, -81, 88, -52, -9, 65, -90, 71, -18, -44, 85, -84, 43, 20, -73, 90, -64, 7, 54, -88, 80, -33, -31, 79, -89, 56, 4, -62, 90, -73, 22, 41, -83, 86, -46, -15, 70, -91, 67, -11, -50, 87, -82, 37, 25, -77, 90, -59, },
  { 64, -71, 22, 37, -80, 90, -61, 7, 50, -86, 85, -48, -9, 62, -90, 79, -36, -24, 73, -91, 70, -20, -38, 81, -89, 59, -4, -52, 87, -84, 46, 11, -64, 90, -78, 33, 25, -73, 90, -69, 18, 41, -82, 88, -57, 2, 54, -87, 83, -44, -13, 65, -90, 77, -31, -28, 75, -90, 67, -15, -43, 83, -88, 56, },
  { 64, -73, 31, 24, -70, 90, -78, 37, 18, -65, 90, -81, 43, 11, -61, 88, -83, 48, 4, -56, 87, -86, 54, -2, -50, 84, -88, 59, -9, -44, 82, -90, 64, -15, -38, 79, -90, 69, -22, -33, 75, -91, 73, -28, -25, 71, -90, 77, -36, -20, 67, -90, 80, -41, -13, 62, -89, 83, -46, -7, 57, -87, 85, -52, },
  { 64, -77, 38, 11, -57, 86, -88, 62, -18, -33, 73, -90, 80, -44, -4, 52, -83, 90, -67, 24, 25, -69, 90, -83, 50, -2, -46, 81, -90, 71, -31, -20, 64, -88, 85, -56, 9, 41, -78, 91, -75, 37, 13, -59, 87, -87, 61, -15, -36, 73, -90, 79, -43, -7, 54, -84, 89, -65, 22, 28, -70, 90, -82, 48, },
  { 64, -79, 46, -2, -43, 77, -90, 81, -50, 7, 38, -73, 90, -83, 54, -11, -36, 71, -90, 84, -57, 15, 31, -69, 89, -86, 61, -20, -25, 65, -88, 87, -64, 24, 22, -62, 87, -88, 67, -28, -18, 59, -85, 90, -70, 33, 13, -56, 83, -90, 73, -37, -9, 52, -82, 90, -75, 41, 4, -48, 80, -91, 78, -44, },
  { 64, -81, 54, -15, -25, 62, -85, 90, -75, 44, -4, -37, 70, -88, 88, -69, 36, 7, -46, 77, -90, 84, -61, 24, 18, -56, 82, -91, 80, -52, 13, 28, -64, 86, -90, 73, -43, 2, 38, -71, 89, -87, 67, -33, -9, 48, -78, 90, -83, 59, -22, -20, 57, -83, 90, -79, 50, -11, -31, 65, -87, 90, -73, 41, },
  { 64, -83, 61, -28, -9, 44, -73, 88, -89, 73, -46, 11, 25, -59, 82, -91, 83, -62, 31, 7, -43, 71, -88, 90, -75, 48, -13, -24, 57, -81, 90, -84, 64, -33, -4, 41, -70, 87, -90, 77, -50, 15, 22, -56, 80, -90, 85, -65, 36, 2, -38, 69, -87, 90, -78, 52, -18, -20, 54, -79, 90, -86, 67, -37, },
  { 64, -84, 67, -41, 9, 24, -54, 77, -89, 90, -78, 56, -25, -7, 38, -65, 83, -91, 85, -69, 43, -11, -22, 52, -75, 88, -90, 79, -57, 28, 4, -37, 64, -83, 90, -86, 70, -44, 13, 20, -50, 73, -88, 90, -80, 59, -31, -2, 36, -62, 82, -90, 87, -71, 46, -15, -18, 48, -73, 87, -90, 81, -61, 33, },
  { 64, -86, 73, -52, 25, 2, -31, 56, -75, 87, -90, 84, -70, 48, -22, -7, 36, -59, 78, -88, 90, -83, 67, -44, 18, 11, -38, 62, -80, 90, -90, 81, -64, 41, -13, -15, 43, -65, 82, -90, 89, -79, 61, -37, 9, 20, -46, 69, -83, 90, -88, 77, -57, 33, -4, -24, 50, -71, 85, -91, 87, -73, 54, -28, },
  { 64, -87, 78, -62, 43, -20, -4, 28, -50, 69, -82, 90, -90, 84, -73, 56, -36, 11, 13, -37, 57, -73, 85, -90, 89, -81, 67, -48, 25, -2, -22, 44, -64, 79, -88, 91, -87, 77, -61, 41, -18, -7, 31, -52, 70, -83, 90, -90, 83, -71, 54, -33, 9, 15, -38, 59, -75, 86, -90, 88, -80, 65, -46, 24, },
  { 64, -88, 82, -71, 57, -41, 22, -2, -18, 37, -54, 69, -80, 87, -90, 90, -83, 73, -61, 44, -25, 7, 13, -33, 50, -65, 78, -86, 90, -90, 85, -77, 64, -48, 31, -11, -9, 28, -46, 62, -75, 84, -90, 90, -87, 79, -67, 52, -36, 15, 4, -24, 43, -59, 73, -83, 89, -91, 88, -81, 70, -56, 38, -20, },
  { 64, -90, 85, -79, 70, -59, 46, -33, 18, -2, -13, 28, -43, 56, -67, 77, -83, 88, -90, 90, -87, 81, -73, 62, -50, 37, -22, 7, 9, -24, 38, -52, 64, -73, 82, -87, 90, -90, 88, -83, 75, -65, 54, -41, 25, -11, -4, 20, -36, 48, -61, 71, -80, 86, -90, 91, -89, 84, -78, 69, -57, 44, -31, 15, },
  { 64, -90, 88, -84, 80, -73, 67, -59, 50, -41, 31, -20, 9, 2, -13, 24, -36, 44, -54, 62, -70, 77, -82, 86, -89, 90, -90, 90, -87, 83, -78, 71, -64, 56, -46, 37, -25, 15, -4, -7, 18, -28, 38, -48, 57, -65, 73, -79, 83, -87, 90, -91, 90, -88, 85, -81, 75, -69, 61, -52, 43, -33, 22, -11, },
  { 64, -90, 90, -88, 87, -84, 82, -79, 75, -71, 67, -62, 57, -52, 46, -41, 36, -28, 22, -15, 9, -2, -4, 11, -18, 24, -31, 37, -43, 48, -54, 59, -64, 69, -73, 77, -80, 83, -85, 87, -89, 90, -90, 91, -90, 90, -88, 86, -83, 81, -78, 73, -70, 65, -61, 56, -50, 44, -38, 33, -25, 20, -13, 7, },
  { 64, -91, 90, -90, 90, -90, 90, -90, 89, -88, 88, -87, 87, -86, 85, -84, 83, -83, 82, -81, 80, -79, 78, -77, 75, -73, 73, -71, 70, -69, 67, -65, 64, -62, 61, -59, 57, -56, 54, -52, 50, -48, 46, -44, 43, -41, 38, -37, 36, -33, 31, -28, 25, -24, 22, -20, 18, -15, 13, -11, 9, -7, 4, -2, }
};
/**
 * \brief Generic partial butterfly functions
 *
 * TODO: description
 *
 * \param TODO
 *
 * \returns TODO
 */

 // Fast DST Algorithm. Full matrix multiplication for DST and Fast DST algorithm
 // gives identical results
static void fast_forward_dst_4_generic(const short* block, short* coeff, int32_t shift)  // input block, output coeff
{
  int32_t i, c[4];
  int32_t rnd_factor = 1 << (shift - 1);
  for (i = 0; i < 4; i++) {
    // int32_termediate Variables
    c[0] = block[4 * i + 0] + block[4 * i + 3];
    c[1] = block[4 * i + 1] + block[4 * i + 3];
    c[2] = block[4 * i + 0] - block[4 * i + 1];
    c[3] = 74 * block[4 * i + 2];

    coeff[i] = (short)((29 * c[0] + 55 * c[1] + c[3] + rnd_factor) >> shift);
    coeff[4 + i] = (short)((74 * (block[4 * i + 0] + block[4 * i + 1] - block[4 * i + 3]) + rnd_factor) >> shift);
    coeff[8 + i] = (short)((29 * c[2] + 55 * c[0] - c[3] + rnd_factor) >> shift);
    coeff[12 + i] = (short)((55 * c[2] - 29 * c[1] + c[3] + rnd_factor) >> shift);
  }
}

static void fast_inverse_dst_4_generic(const short* tmp, short* block, int shift)  // input tmp, output block
{
  int i, c[4];
  int rnd_factor = 1 << (shift - 1);
  for (i = 0; i < 4; i++) {
    // Intermediate Variables
    c[0] = tmp[i] + tmp[8 + i];
    c[1] = tmp[8 + i] + tmp[12 + i];
    c[2] = tmp[i] - tmp[12 + i];
    c[3] = 74 * tmp[4 + i];

    block[4 * i + 0] = (short)CLIP(-32768, 32767, (29 * c[0] + 55 * c[1] + c[3] + rnd_factor) >> shift);
    block[4 * i + 1] = (short)CLIP(-32768, 32767, (55 * c[2] - 29 * c[1] + c[3] + rnd_factor) >> shift);
    block[4 * i + 2] = (short)CLIP(-32768, 32767, (74 * (tmp[i] - tmp[8 + i] + tmp[12 + i]) + rnd_factor) >> shift);
    block[4 * i + 3] = (short)CLIP(-32768, 32767, (55 * c[0] + 29 * c[2] - c[3] + rnd_factor) >> shift);
  }
}


static void partial_butterfly_4_generic(const short* src, short* dst,
  int32_t shift)
{
  int32_t j;
  int32_t e[2], o[2];
  int32_t add = 1 << (shift - 1);
  const int32_t line = 4;

  for (j = 0; j < line; j++) {
    // E and O
    e[0] = src[0] + src[3];
    o[0] = src[0] - src[3];
    e[1] = src[1] + src[2];
    o[1] = src[1] - src[2];

    dst[0] = (short)((uvg_g_dct_4[0][0] * e[0] + uvg_g_dct_4[0][1] * e[1] + add) >> shift);
    dst[2 * line] = (short)((uvg_g_dct_4[2][0] * e[0] + uvg_g_dct_4[2][1] * e[1] + add) >> shift);
    dst[line] = (short)((uvg_g_dct_4[1][0] * o[0] + uvg_g_dct_4[1][1] * o[1] + add) >> shift);
    dst[3 * line] = (short)((uvg_g_dct_4[3][0] * o[0] + uvg_g_dct_4[3][1] * o[1] + add) >> shift);

    src += 4;
    dst++;
  }
}


static void partial_butterfly_inverse_4_generic(const short* src, short* dst,
  int shift)
{
  int j;
  int e[2], o[2];
  int add = 1 << (shift - 1);
  const int32_t line = 4;

  for (j = 0; j < line; j++) {
    // Utilizing symmetry properties to the maximum to minimize the number of multiplications
    o[0] = uvg_g_dct_4[1][0] * src[line] + uvg_g_dct_4[3][0] * src[3 * line];
    o[1] = uvg_g_dct_4[1][1] * src[line] + uvg_g_dct_4[3][1] * src[3 * line];
    e[0] = uvg_g_dct_4[0][0] * src[0] + uvg_g_dct_4[2][0] * src[2 * line];
    e[1] = uvg_g_dct_4[0][1] * src[0] + uvg_g_dct_4[2][1] * src[2 * line];

    // Combining even and odd terms at each hierarchy levels to calculate the final spatial domain vector
    dst[0] = (short)CLIP(-32768, 32767, (e[0] + o[0] + add) >> shift);
    dst[1] = (short)CLIP(-32768, 32767, (e[1] + o[1] + add) >> shift);
    dst[2] = (short)CLIP(-32768, 32767, (e[1] - o[1] + add) >> shift);
    dst[3] = (short)CLIP(-32768, 32767, (e[0] - o[0] + add) >> shift);

    src++;
    dst += 4;
  }
}


static void partial_butterfly_8_generic(const short* src, short* dst,
  int32_t shift)
{
  int32_t j, k;
  int32_t e[4], o[4];
  int32_t ee[2], eo[2];
  int32_t add = 1 << (shift - 1);
  const int32_t line = 8;

  for (j = 0; j < line; j++) {
    // E and O
    for (k = 0; k < 4; k++) {
      e[k] = src[k] + src[7 - k];
      o[k] = src[k] - src[7 - k];
    }
    // EE and EO
    ee[0] = e[0] + e[3];
    eo[0] = e[0] - e[3];
    ee[1] = e[1] + e[2];
    eo[1] = e[1] - e[2];

    dst[0] = (short)((uvg_g_dct_8[0][0] * ee[0] + uvg_g_dct_8[0][1] * ee[1] + add) >> shift);
    dst[4 * line] = (short)((uvg_g_dct_8[4][0] * ee[0] + uvg_g_dct_8[4][1] * ee[1] + add) >> shift);
    dst[2 * line] = (short)((uvg_g_dct_8[2][0] * eo[0] + uvg_g_dct_8[2][1] * eo[1] + add) >> shift);
    dst[6 * line] = (short)((uvg_g_dct_8[6][0] * eo[0] + uvg_g_dct_8[6][1] * eo[1] + add) >> shift);

    dst[line] = (short)((uvg_g_dct_8[1][0] * o[0] + uvg_g_dct_8[1][1] * o[1] + uvg_g_dct_8[1][2] * o[2] + uvg_g_dct_8[1][3] * o[3] + add) >> shift);
    dst[3 * line] = (short)((uvg_g_dct_8[3][0] * o[0] + uvg_g_dct_8[3][1] * o[1] + uvg_g_dct_8[3][2] * o[2] + uvg_g_dct_8[3][3] * o[3] + add) >> shift);
    dst[5 * line] = (short)((uvg_g_dct_8[5][0] * o[0] + uvg_g_dct_8[5][1] * o[1] + uvg_g_dct_8[5][2] * o[2] + uvg_g_dct_8[5][3] * o[3] + add) >> shift);
    dst[7 * line] = (short)((uvg_g_dct_8[7][0] * o[0] + uvg_g_dct_8[7][1] * o[1] + uvg_g_dct_8[7][2] * o[2] + uvg_g_dct_8[7][3] * o[3] + add) >> shift);

    src += 8;
    dst++;
  }
}


static void partial_butterfly_inverse_8_generic(const int16_t* src, int16_t* dst,
  int32_t shift)
{
  int32_t j, k;
  int32_t e[4], o[4];
  int32_t ee[2], eo[2];
  int32_t add = 1 << (shift - 1);
  const int32_t line = 8;

  for (j = 0; j < line; j++) {
    // Utilizing symmetry properties to the maximum to minimize the number of multiplications
    for (k = 0; k < 4; k++) {
      o[k] = uvg_g_dct_8[1][k] * src[line] + uvg_g_dct_8[3][k] * src[3 * line] + uvg_g_dct_8[5][k] * src[5 * line] + uvg_g_dct_8[7][k] * src[7 * line];
    }

    eo[0] = uvg_g_dct_8[2][0] * src[2 * line] + uvg_g_dct_8[6][0] * src[6 * line];
    eo[1] = uvg_g_dct_8[2][1] * src[2 * line] + uvg_g_dct_8[6][1] * src[6 * line];
    ee[0] = uvg_g_dct_8[0][0] * src[0] + uvg_g_dct_8[4][0] * src[4 * line];
    ee[1] = uvg_g_dct_8[0][1] * src[0] + uvg_g_dct_8[4][1] * src[4 * line];

    // Combining even and odd terms at each hierarchy levels to calculate the final spatial domain vector
    e[0] = ee[0] + eo[0];
    e[3] = ee[0] - eo[0];
    e[1] = ee[1] + eo[1];
    e[2] = ee[1] - eo[1];
    for (k = 0; k < 4; k++) {
      dst[k] = (int16_t)MAX(-32768, MIN(32767, (e[k] + o[k] + add) >> shift));
      dst[k + 4] = (int16_t)MAX(-32768, MIN(32767, (e[3 - k] - o[3 - k] + add) >> shift));
    }
    src++;
    dst += 8;
  }
}


static void partial_butterfly_16_generic(const short* src, short* dst,
  int32_t shift)
{
  int32_t j, k;
  int32_t e[8], o[8];
  int32_t ee[4], eo[4];
  int32_t eee[2], eeo[2];
  int32_t add = 1 << (shift - 1);
  const int32_t line = 16;

  for (j = 0; j < line; j++) {
    // E and O
    for (k = 0; k < 8; k++) {
      e[k] = src[k] + src[15 - k];
      o[k] = src[k] - src[15 - k];
    }
    // EE and EO
    for (k = 0; k < 4; k++) {
      ee[k] = e[k] + e[7 - k];
      eo[k] = e[k] - e[7 - k];
    }
    // EEE and EEO
    eee[0] = ee[0] + ee[3];
    eeo[0] = ee[0] - ee[3];
    eee[1] = ee[1] + ee[2];
    eeo[1] = ee[1] - ee[2];

    dst[0] = (short)((uvg_g_dct_16[0][0] * eee[0] + uvg_g_dct_16[0][1] * eee[1] + add) >> shift);
    dst[8 * line] = (short)((uvg_g_dct_16[8][0] * eee[0] + uvg_g_dct_16[8][1] * eee[1] + add) >> shift);
    dst[4 * line] = (short)((uvg_g_dct_16[4][0] * eeo[0] + uvg_g_dct_16[4][1] * eeo[1] + add) >> shift);
    dst[12 * line] = (short)((uvg_g_dct_16[12][0] * eeo[0] + uvg_g_dct_16[12][1] * eeo[1] + add) >> shift);

    for (k = 2; k < 16; k += 4) {
      dst[k * line] = (short)((uvg_g_dct_16[k][0] * eo[0] + uvg_g_dct_16[k][1] * eo[1] + uvg_g_dct_16[k][2] * eo[2] + uvg_g_dct_16[k][3] * eo[3] + add) >> shift);
    }

    for (k = 1; k < 16; k += 2) {
      dst[k * line] = (short)((uvg_g_dct_16[k][0] * o[0] + uvg_g_dct_16[k][1] * o[1] + uvg_g_dct_16[k][2] * o[2] + uvg_g_dct_16[k][3] * o[3] +
        uvg_g_dct_16[k][4] * o[4] + uvg_g_dct_16[k][5] * o[5] + uvg_g_dct_16[k][6] * o[6] + uvg_g_dct_16[k][7] * o[7] + add) >> shift);
    }

    src += 16;
    dst++;
  }
}


static void partial_butterfly_inverse_16_generic(const int16_t* src, int16_t* dst,
  int32_t shift)
{
  int32_t j, k;
  int32_t e[8], o[8];
  int32_t ee[4], eo[4];
  int32_t eee[2], eeo[2];
  int32_t add = 1 << (shift - 1);
  const int32_t line = 16;

  for (j = 0; j < line; j++) {
    // Utilizing symmetry properties to the maximum to minimize the number of multiplications
    for (k = 0; k < 8; k++) {
      o[k] = uvg_g_dct_16[1][k] * src[line] + uvg_g_dct_16[3][k] * src[3 * line] + uvg_g_dct_16[5][k] * src[5 * line] + uvg_g_dct_16[7][k] * src[7 * line] +
        uvg_g_dct_16[9][k] * src[9 * line] + uvg_g_dct_16[11][k] * src[11 * line] + uvg_g_dct_16[13][k] * src[13 * line] + uvg_g_dct_16[15][k] * src[15 * line];
    }
    for (k = 0; k < 4; k++) {
      eo[k] = uvg_g_dct_16[2][k] * src[2 * line] + uvg_g_dct_16[6][k] * src[6 * line] + uvg_g_dct_16[10][k] * src[10 * line] + uvg_g_dct_16[14][k] * src[14 * line];
    }
    eeo[0] = uvg_g_dct_16[4][0] * src[4 * line] + uvg_g_dct_16[12][0] * src[12 * line];
    eee[0] = uvg_g_dct_16[0][0] * src[0] + uvg_g_dct_16[8][0] * src[8 * line];
    eeo[1] = uvg_g_dct_16[4][1] * src[4 * line] + uvg_g_dct_16[12][1] * src[12 * line];
    eee[1] = uvg_g_dct_16[0][1] * src[0] + uvg_g_dct_16[8][1] * src[8 * line];

    // Combining even and odd terms at each hierarchy levels to calculate the final spatial domain vector
    for (k = 0; k < 2; k++) {
      ee[k] = eee[k] + eeo[k];
      ee[k + 2] = eee[1 - k] - eeo[1 - k];
    }
    for (k = 0; k < 4; k++) {
      e[k] = ee[k] + eo[k];
      e[k + 4] = ee[3 - k] - eo[3 - k];
    }
    for (k = 0; k < 8; k++) {
      dst[k] = (short)MAX(-32768, MIN(32767, (e[k] + o[k] + add) >> shift));
      dst[k + 8] = (short)MAX(-32768, MIN(32767, (e[7 - k] - o[7 - k] + add) >> shift));
    }
    src++;
    dst += 16;
  }
}


static void partial_butterfly_32_generic(const short* src, short* dst,
  int32_t shift)
{
  int32_t j, k;
  int32_t e[16], o[16];
  int32_t ee[8], eo[8];
  int32_t eee[4], eeo[4];
  int32_t eeee[2], eeeo[2];
  int32_t add = 1 << (shift - 1);
  const int32_t line = 32;

  for (j = 0; j < line; j++) {
    // E and O
    for (k = 0; k < 16; k++) {
      e[k] = src[k] + src[31 - k];
      o[k] = src[k] - src[31 - k];
    }
    // EE and EO
    for (k = 0; k < 8; k++) {
      ee[k] = e[k] + e[15 - k];
      eo[k] = e[k] - e[15 - k];
    }
    // EEE and EEO
    for (k = 0; k < 4; k++) {
      eee[k] = ee[k] + ee[7 - k];
      eeo[k] = ee[k] - ee[7 - k];
    }
    // EEEE and EEEO
    eeee[0] = eee[0] + eee[3];
    eeeo[0] = eee[0] - eee[3];
    eeee[1] = eee[1] + eee[2];
    eeeo[1] = eee[1] - eee[2];

    dst[0] = (short)((uvg_g_dct_32[0][0] * eeee[0] + uvg_g_dct_32[0][1] * eeee[1] + add) >> shift);
    dst[16 * line] = (short)((uvg_g_dct_32[16][0] * eeee[0] + uvg_g_dct_32[16][1] * eeee[1] + add) >> shift);
    dst[8 * line] = (short)((uvg_g_dct_32[8][0] * eeeo[0] + uvg_g_dct_32[8][1] * eeeo[1] + add) >> shift);
    dst[24 * line] = (short)((uvg_g_dct_32[24][0] * eeeo[0] + uvg_g_dct_32[24][1] * eeeo[1] + add) >> shift);
    for (k = 4; k < 32; k += 8) {
      dst[k * line] = (short)((uvg_g_dct_32[k][0] * eeo[0] + uvg_g_dct_32[k][1] * eeo[1] + uvg_g_dct_32[k][2] * eeo[2] + uvg_g_dct_32[k][3] * eeo[3] + add) >> shift);
    }
    for (k = 2; k < 32; k += 4) {
      dst[k * line] = (short)((uvg_g_dct_32[k][0] * eo[0] + uvg_g_dct_32[k][1] * eo[1] + uvg_g_dct_32[k][2] * eo[2] + uvg_g_dct_32[k][3] * eo[3] +
        uvg_g_dct_32[k][4] * eo[4] + uvg_g_dct_32[k][5] * eo[5] + uvg_g_dct_32[k][6] * eo[6] + uvg_g_dct_32[k][7] * eo[7] + add) >> shift);
    }
    for (k = 1; k < 32; k += 2) {
      dst[k * line] = (short)((uvg_g_dct_32[k][0] * o[0] + uvg_g_dct_32[k][1] * o[1] + uvg_g_dct_32[k][2] * o[2] + uvg_g_dct_32[k][3] * o[3] +
        uvg_g_dct_32[k][4] * o[4] + uvg_g_dct_32[k][5] * o[5] + uvg_g_dct_32[k][6] * o[6] + uvg_g_dct_32[k][7] * o[7] +
        uvg_g_dct_32[k][8] * o[8] + uvg_g_dct_32[k][9] * o[9] + uvg_g_dct_32[k][10] * o[10] + uvg_g_dct_32[k][11] * o[11] +
        uvg_g_dct_32[k][12] * o[12] + uvg_g_dct_32[k][13] * o[13] + uvg_g_dct_32[k][14] * o[14] + uvg_g_dct_32[k][15] * o[15] + add) >> shift);
    }
    src += 32;
    dst++;
  }
}


static void partial_butterfly_inverse_32_generic(const int16_t* src, int16_t* dst,
  int32_t shift)
{
  int32_t j, k;
  int32_t e[16], o[16];
  int32_t ee[8], eo[8];
  int32_t eee[4], eeo[4];
  int32_t eeee[2], eeeo[2];
  int32_t add = 1 << (shift - 1);
  const int32_t line = 32;

  for (j = 0; j < line; j++) {
    // Utilizing symmetry properties to the maximum to minimize the number of multiplications
    for (k = 0; k < 16; k++) {
      o[k] = uvg_g_dct_32[1][k] * src[line] + uvg_g_dct_32[3][k] * src[3 * line] + uvg_g_dct_32[5][k] * src[5 * line] + uvg_g_dct_32[7][k] * src[7 * line] +
        uvg_g_dct_32[9][k] * src[9 * line] + uvg_g_dct_32[11][k] * src[11 * line] + uvg_g_dct_32[13][k] * src[13 * line] + uvg_g_dct_32[15][k] * src[15 * line] +
        uvg_g_dct_32[17][k] * src[17 * line] + uvg_g_dct_32[19][k] * src[19 * line] + uvg_g_dct_32[21][k] * src[21 * line] + uvg_g_dct_32[23][k] * src[23 * line] +
        uvg_g_dct_32[25][k] * src[25 * line] + uvg_g_dct_32[27][k] * src[27 * line] + uvg_g_dct_32[29][k] * src[29 * line] + uvg_g_dct_32[31][k] * src[31 * line];
    }
    for (k = 0; k < 8; k++) {
      eo[k] = uvg_g_dct_32[2][k] * src[2 * line] + uvg_g_dct_32[6][k] * src[6 * line] + uvg_g_dct_32[10][k] * src[10 * line] + uvg_g_dct_32[14][k] * src[14 * line] +
        uvg_g_dct_32[18][k] * src[18 * line] + uvg_g_dct_32[22][k] * src[22 * line] + uvg_g_dct_32[26][k] * src[26 * line] + uvg_g_dct_32[30][k] * src[30 * line];
    }
    for (k = 0; k < 4; k++) {
      eeo[k] = uvg_g_dct_32[4][k] * src[4 * line] + uvg_g_dct_32[12][k] * src[12 * line] + uvg_g_dct_32[20][k] * src[20 * line] + uvg_g_dct_32[28][k] * src[28 * line];
    }
    eeeo[0] = uvg_g_dct_32[8][0] * src[8 * line] + uvg_g_dct_32[24][0] * src[24 * line];
    eeeo[1] = uvg_g_dct_32[8][1] * src[8 * line] + uvg_g_dct_32[24][1] * src[24 * line];
    eeee[0] = uvg_g_dct_32[0][0] * src[0] + uvg_g_dct_32[16][0] * src[16 * line];
    eeee[1] = uvg_g_dct_32[0][1] * src[0] + uvg_g_dct_32[16][1] * src[16 * line];

    // Combining even and odd terms at each hierarchy levels to calculate the final spatial domain vector
    eee[0] = eeee[0] + eeeo[0];
    eee[3] = eeee[0] - eeeo[0];
    eee[1] = eeee[1] + eeeo[1];
    eee[2] = eeee[1] - eeeo[1];
    for (k = 0; k < 4; k++) {
      ee[k] = eee[k] + eeo[k];
      ee[k + 4] = eee[3 - k] - eeo[3 - k];
    }
    for (k = 0; k < 8; k++) {
      e[k] = ee[k] + eo[k];
      e[k + 8] = ee[7 - k] - eo[7 - k];
    }
    for (k = 0; k < 16; k++) {
      dst[k] = (short)MAX(-32768, MIN(32767, (e[k] + o[k] + add) >> shift));
      dst[k + 16] = (short)MAX(-32768, MIN(32767, (e[15 - k] - o[15 - k] + add) >> shift));
    }
    src++;
    dst += 32;
  }
}

#define DCT_NXN_GENERIC(n) \
static void dct_ ## n ## x ## n ## _generic(int8_t bitdepth, const int16_t *input, int16_t *output) { \
\
  int16_t tmp[ n * n ]; \
  int32_t shift_1st = uvg_g_convert_to_bit[ n ] + 1 + (bitdepth - 8); \
  int32_t shift_2nd = uvg_g_convert_to_bit[ n ] + 8; \
\
  partial_butterfly_ ## n ## _generic(input, tmp, shift_1st); \
  partial_butterfly_ ## n ## _generic(tmp, output, shift_2nd); \
}

#define IDCT_NXN_GENERIC(n) \
static void idct_ ## n ## x ## n ## _generic(int8_t bitdepth, const int16_t *input, int16_t *output) { \
\
  int16_t tmp[ n * n ]; \
  int32_t shift_1st = 7; \
  int32_t shift_2nd = 12 - (bitdepth - 8); \
\
  partial_butterfly_inverse_ ## n ## _generic(input, tmp, shift_1st); \
  partial_butterfly_inverse_ ## n ## _generic(tmp, output, shift_2nd); \
}

DCT_NXN_GENERIC(4);
DCT_NXN_GENERIC(8);
DCT_NXN_GENERIC(16);
DCT_NXN_GENERIC(32);

IDCT_NXN_GENERIC(4);
IDCT_NXN_GENERIC(8);
IDCT_NXN_GENERIC(16);
IDCT_NXN_GENERIC(32);

static void fast_forward_dst_4x4_generic(int8_t bitdepth, const int16_t* input, int16_t* output)
{
  int16_t tmp[4 * 4];
  int32_t shift_1st = uvg_g_convert_to_bit[4] + 1 + (bitdepth - 8);
  int32_t shift_2nd = uvg_g_convert_to_bit[4] + 8;

  fast_forward_dst_4_generic(input, tmp, shift_1st);
  fast_forward_dst_4_generic(tmp, output, shift_2nd);
}

static void fast_inverse_dst_4x4_generic(int8_t bitdepth, const int16_t* input, int16_t* output)
{
  int16_t tmp[4 * 4];
  int32_t shift_1st = 7;
  int32_t shift_2nd = 12 - (bitdepth - 8);

  fast_inverse_dst_4_generic(input, tmp, shift_1st);
  fast_inverse_dst_4_generic(tmp, output, shift_2nd);
}


// DCT-2
#define DEFINE_DCT2_P2_MATRIX(a) \
{ \
   a,  a, \
   a, -a  \
}

#define DEFINE_DCT2_P4_MATRIX(a,b,c) \
{ \
   a,  a,  a,  a, \
   b,  c, -c, -b, \
   a, -a, -a,  a, \
   c, -b,  b, -c, \
}

#define DEFINE_DCT2_P8_MATRIX(a,b,c,d,e,f,g) \
{ \
   a,  a,  a,  a,  a,  a,  a,  a, \
   d,  e,  f,  g, -g, -f, -e, -d, \
   b,  c, -c, -b, -b, -c,  c,  b, \
   e, -g, -d, -f,  f,  d,  g, -e, \
   a, -a, -a,  a,  a, -a, -a,  a, \
   f, -d,  g,  e, -e, -g,  d, -f, \
   c, -b,  b, -c, -c,  b, -b,  c, \
   g, -f,  e, -d,  d, -e,  f, -g, \
}

#define DEFINE_DCT2_P16_MATRIX(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o) \
{ \
   a,  a,  a,  a,  a,  a,  a,  a,  a,  a,  a,  a,  a,  a,  a,  a, \
   h,  i,  j,  k,  l,  m,  n,  o, -o, -n, -m, -l, -k, -j, -i, -h, \
   d,  e,  f,  g, -g, -f, -e, -d, -d, -e, -f, -g,  g,  f,  e,  d, \
   i,  l,  o, -m, -j, -h, -k, -n,  n,  k,  h,  j,  m, -o, -l, -i, \
   b,  c, -c, -b, -b, -c,  c,  b,  b,  c, -c, -b, -b, -c,  c,  b, \
   j,  o, -k, -i, -n,  l,  h,  m, -m, -h, -l,  n,  i,  k, -o, -j, \
   e, -g, -d, -f,  f,  d,  g, -e, -e,  g,  d,  f, -f, -d, -g,  e, \
   k, -m, -i,  o,  h,  n, -j, -l,  l,  j, -n, -h, -o,  i,  m, -k, \
   a, -a, -a,  a,  a, -a, -a,  a,  a, -a, -a,  a,  a, -a, -a,  a, \
   l, -j, -n,  h, -o, -i,  m,  k, -k, -m,  i,  o, -h,  n,  j, -l, \
   f, -d,  g,  e, -e, -g,  d, -f, -f,  d, -g, -e,  e,  g, -d,  f, \
   m, -h,  l,  n, -i,  k,  o, -j,  j, -o, -k,  i, -n, -l,  h, -m, \
   c, -b,  b, -c, -c,  b, -b,  c,  c, -b,  b, -c, -c,  b, -b,  c, \
   n, -k,  h, -j,  m,  o, -l,  i, -i,  l, -o, -m,  j, -h,  k, -n, \
   g, -f,  e, -d,  d, -e,  f, -g, -g,  f, -e,  d, -d,  e, -f,  g, \
   o, -n,  m, -l,  k, -j,  i, -h,  h, -i,  j, -k,  l, -m,  n, -o, \
}

#define DEFINE_DCT2_P32_MATRIX(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E) \
{ \
   a,  a,  a,  a,  a,  a,  a,  a,  a,  a,  a,  a,  a,  a,  a,  a,  a,  a,  a,  a,  a,  a,  a,  a,  a,  a,  a,  a,  a,  a,  a,  a, \
   p,  q,  r,  s,  t,  u,  v,  w,  x,  y,  z,  A,  B,  C,  D,  E, -E, -D, -C, -B, -A, -z, -y, -x, -w, -v, -u, -t, -s, -r, -q, -p, \
   h,  i,  j,  k,  l,  m,  n,  o, -o, -n, -m, -l, -k, -j, -i, -h, -h, -i, -j, -k, -l, -m, -n, -o,  o,  n,  m,  l,  k,  j,  i,  h, \
   q,  t,  w,  z,  C, -E, -B, -y, -v, -s, -p, -r, -u, -x, -A, -D,  D,  A,  x,  u,  r,  p,  s,  v,  y,  B,  E, -C, -z, -w, -t, -q, \
   d,  e,  f,  g, -g, -f, -e, -d, -d, -e, -f, -g,  g,  f,  e,  d,  d,  e,  f,  g, -g, -f, -e, -d, -d, -e, -f, -g,  g,  f,  e,  d, \
   r,  w,  B, -D, -y, -t, -p, -u, -z, -E,  A,  v,  q,  s,  x,  C, -C, -x, -s, -q, -v, -A,  E,  z,  u,  p,  t,  y,  D, -B, -w, -r, \
   i,  l,  o, -m, -j, -h, -k, -n,  n,  k,  h,  j,  m, -o, -l, -i, -i, -l, -o,  m,  j,  h,  k,  n, -n, -k, -h, -j, -m,  o,  l,  i, \
   s,  z, -D, -w, -p, -v, -C,  A,  t,  r,  y, -E, -x, -q, -u, -B,  B,  u,  q,  x,  E, -y, -r, -t, -A,  C,  v,  p,  w,  D, -z, -s, \
   b,  c, -c, -b, -b, -c,  c,  b,  b,  c, -c, -b, -b, -c,  c,  b,  b,  c, -c, -b, -b, -c,  c,  b,  b,  c, -c, -b, -b, -c,  c,  b, \
   t,  C, -y, -p, -x,  D,  u,  s,  B, -z, -q, -w,  E,  v,  r,  A, -A, -r, -v, -E,  w,  q,  z, -B, -s, -u, -D,  x,  p,  y, -C, -t, \
   j,  o, -k, -i, -n,  l,  h,  m, -m, -h, -l,  n,  i,  k, -o, -j, -j, -o,  k,  i,  n, -l, -h, -m,  m,  h,  l, -n, -i, -k,  o,  j, \
   u, -E, -t, -v,  D,  s,  w, -C, -r, -x,  B,  q,  y, -A, -p, -z,  z,  p,  A, -y, -q, -B,  x,  r,  C, -w, -s, -D,  v,  t,  E, -u, \
   e, -g, -d, -f,  f,  d,  g, -e, -e,  g,  d,  f, -f, -d, -g,  e,  e, -g, -d, -f,  f,  d,  g, -e, -e,  g,  d,  f, -f, -d, -g,  e, \
   v, -B, -p, -C,  u,  w, -A, -q, -D,  t,  x, -z, -r, -E,  s,  y, -y, -s,  E,  r,  z, -x, -t,  D,  q,  A, -w, -u,  C,  p,  B, -v, \
   k, -m, -i,  o,  h,  n, -j, -l,  l,  j, -n, -h, -o,  i,  m, -k, -k,  m,  i, -o, -h, -n,  j,  l, -l, -j,  n,  h,  o, -i, -m,  k, \
   w, -y, -u,  A,  s, -C, -q,  E,  p,  D, -r, -B,  t,  z, -v, -x,  x,  v, -z, -t,  B,  r, -D, -p, -E,  q,  C, -s, -A,  u,  y, -w, \
   a, -a, -a,  a,  a, -a, -a,  a,  a, -a, -a,  a,  a, -a, -a,  a,  a, -a, -a,  a,  a, -a, -a,  a,  a, -a, -a,  a,  a, -a, -a,  a, \
   x, -v, -z,  t,  B, -r, -D,  p, -E, -q,  C,  s, -A, -u,  y,  w, -w, -y,  u,  A, -s, -C,  q,  E, -p,  D,  r, -B, -t,  z,  v, -x, \
   l, -j, -n,  h, -o, -i,  m,  k, -k, -m,  i,  o, -h,  n,  j, -l, -l,  j,  n, -h,  o,  i, -m, -k,  k,  m, -i, -o,  h, -n, -j,  l, \
   y, -s, -E,  r, -z, -x,  t,  D, -q,  A,  w, -u, -C,  p, -B, -v,  v,  B, -p,  C,  u, -w, -A,  q, -D, -t,  x,  z, -r,  E,  s, -y, \
   f, -d,  g,  e, -e, -g,  d, -f, -f,  d, -g, -e,  e,  g, -d,  f,  f, -d,  g,  e, -e, -g,  d, -f, -f,  d, -g, -e,  e,  g, -d,  f, \
   z, -p,  A,  y, -q,  B,  x, -r,  C,  w, -s,  D,  v, -t,  E,  u, -u, -E,  t, -v, -D,  s, -w, -C,  r, -x, -B,  q, -y, -A,  p, -z, \
   m, -h,  l,  n, -i,  k,  o, -j,  j, -o, -k,  i, -n, -l,  h, -m, -m,  h, -l, -n,  i, -k, -o,  j, -j,  o,  k, -i,  n,  l, -h,  m, \
   A, -r,  v, -E, -w,  q, -z, -B,  s, -u,  D,  x, -p,  y,  C, -t,  t, -C, -y,  p, -x, -D,  u, -s,  B,  z, -q,  w,  E, -v,  r, -A, \
   c, -b,  b, -c, -c,  b, -b,  c,  c, -b,  b, -c, -c,  b, -b,  c,  c, -b,  b, -c, -c,  b, -b,  c,  c, -b,  b, -c, -c,  b, -b,  c, \
   B, -u,  q, -x,  E,  y, -r,  t, -A, -C,  v, -p,  w, -D, -z,  s, -s,  z,  D, -w,  p, -v,  C,  A, -t,  r, -y, -E,  x, -q,  u, -B, \
   n, -k,  h, -j,  m,  o, -l,  i, -i,  l, -o, -m,  j, -h,  k, -n, -n,  k, -h,  j, -m, -o,  l, -i,  i, -l,  o,  m, -j,  h, -k,  n, \
   C, -x,  s, -q,  v, -A, -E,  z, -u,  p, -t,  y, -D, -B,  w, -r,  r, -w,  B,  D, -y,  t, -p,  u, -z,  E,  A, -v,  q, -s,  x, -C, \
   g, -f,  e, -d,  d, -e,  f, -g, -g,  f, -e,  d, -d,  e, -f,  g,  g, -f,  e, -d,  d, -e,  f, -g, -g,  f, -e,  d, -d,  e, -f,  g, \
   D, -A,  x, -u,  r, -p,  s, -v,  y, -B,  E,  C, -z,  w, -t,  q, -q,  t, -w,  z, -C, -E,  B, -y,  v, -s,  p, -r,  u, -x,  A, -D, \
   o, -n,  m, -l,  k, -j,  i, -h,  h, -i,  j, -k,  l, -m,  n, -o, -o,  n, -m,  l, -k,  j, -i,  h, -h,  i, -j,  k, -l,  m, -n,  o, \
   E, -D,  C, -B,  A, -z,  y, -x,  w, -v,  u, -t,  s, -r,  q, -p,  p, -q,  r, -s,  t, -u,  v, -w,  x, -y,  z, -A,  B, -C,  D, -E, \
}

// DST-7
#define DEFINE_DST7_P4_MATRIX(a,b,c,d) \
{ \
    a,  b,  c,  d , \
    c,  c,  0, -c , \
    d, -a, -c,  b , \
    b, -d,  c, -a , \
}

#define DEFINE_DST7_P8_MATRIX(a,b,c,d,e,f,g,h) \
{ \
    a,  b,  c,  d,  e,  f,  g,  h, \
    c,  f,  h,  e,  b, -a, -d, -g, \
    e,  g,  b, -c, -h, -d,  a,  f, \
    g,  c, -d, -f,  a,  h,  b, -e, \
    h, -a, -g,  b,  f, -c, -e,  d, \
    f, -e, -a,  g, -d, -b,  h, -c, \
    d, -h,  e, -a, -c,  g, -f,  b, \
    b, -d,  f, -h,  g, -e,  c, -a, \
}

#define DEFINE_DST7_P16_MATRIX(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) \
{ \
    a,  b,  c,  d,  e,  f,  g,  h,  i,  j,  k,  l,  m,  n,  o,  p, \
    c,  f,  i,  l,  o,  o,  l,  i,  f,  c,  0, -c, -f, -i, -l, -o, \
    e,  j,  o,  m,  h,  c, -b, -g, -l, -p, -k, -f, -a,  d,  i,  n, \
    g,  n,  l,  e, -b, -i, -p, -j, -c,  d,  k,  o,  h,  a, -f, -m, \
    i,  o,  f, -c, -l, -l, -c,  f,  o,  i,  0, -i, -o, -f,  c,  l, \
    k,  k,  0, -k, -k,  0,  k,  k,  0, -k, -k,  0,  k,  k,  0, -k, \
    m,  g, -f, -n, -a,  l,  h, -e, -o, -b,  k,  i, -d, -p, -c,  j, \
    o,  c, -l, -f,  i,  i, -f, -l,  c,  o,  0, -o, -c,  l,  f, -i, \
    p, -a, -o,  b,  n, -c, -m,  d,  l, -e, -k,  f,  j, -g, -i,  h, \
    n, -e, -i,  j,  d, -o,  a,  m, -f, -h,  k,  c, -p,  b,  l, -g, \
    l, -i, -c,  o, -f, -f,  o, -c, -i,  l,  0, -l,  i,  c, -o,  f, \
    j, -m,  c,  g, -p,  f,  d, -n,  i,  a, -k,  l, -b, -h,  o, -e, \
    h, -p,  i, -a, -g,  o, -j,  b,  f, -n,  k, -c, -e,  m, -l,  d, \
    f, -l,  o, -i,  c,  c, -i,  o, -l,  f,  0, -f,  l, -o,  i, -c, \
    d, -h,  l, -p,  m, -i,  e, -a, -c,  g, -k,  o, -n,  j, -f,  b, \
    b, -d,  f, -h,  j, -l,  n, -p,  o, -m,  k, -i,  g, -e,  c, -a, \
}

#define DEFINE_DST7_P32_MATRIX(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F) \
{ \
    a,  b,  c,  d,  e,  f,  g,  h,  i,  j,  k,  l,  m,  n,  o,  p,  q,  r,  s,  t,  u,  v,  w,  x,  y,  z,  A,  B,  C,  D,  E,  F, \
    c,  f,  i,  l,  o,  r,  u,  x,  A,  D,  F,  C,  z,  w,  t,  q,  n,  k,  h,  e,  b, -a, -d, -g, -j, -m, -p, -s, -v, -y, -B, -E, \
    e,  j,  o,  t,  y,  D,  D,  y,  t,  o,  j,  e,  0, -e, -j, -o, -t, -y, -D, -D, -y, -t, -o, -j, -e,  0,  e,  j,  o,  t,  y,  D, \
    g,  n,  u,  B,  D,  w,  p,  i,  b, -e, -l, -s, -z, -F, -y, -r, -k, -d,  c,  j,  q,  x,  E,  A,  t,  m,  f, -a, -h, -o, -v, -C, \
    i,  r,  A,  C,  t,  k,  b, -g, -p, -y, -E, -v, -m, -d,  e,  n,  w,  F,  x,  o,  f, -c, -l, -u, -D, -z, -q, -h,  a,  j,  s,  B, \
    k,  v,  F,  u,  j, -a, -l, -w, -E, -t, -i,  b,  m,  x,  D,  s,  h, -c, -n, -y, -C, -r, -g,  d,  o,  z,  B,  q,  f, -e, -p, -A, \
    m,  z,  z,  m,  0, -m, -z, -z, -m,  0,  m,  z,  z,  m,  0, -m, -z, -z, -m,  0,  m,  z,  z,  m,  0, -m, -z, -z, -m,  0,  m,  z, \
    o,  D,  t,  e, -j, -y, -y, -j,  e,  t,  D,  o,  0, -o, -D, -t, -e,  j,  y,  y,  j, -e, -t, -D, -o,  0,  o,  D,  t,  e, -j, -y, \
    q,  E,  n, -c, -t, -B, -k,  f,  w,  y,  h, -i, -z, -v, -e,  l,  C,  s,  b, -o, -F, -p,  a,  r,  D,  m, -d, -u, -A, -j,  g,  x, \
    s,  A,  h, -k, -D, -p,  c,  v,  x,  e, -n, -F, -m,  f,  y,  u,  b, -q, -C, -j,  i,  B,  r, -a, -t, -z, -g,  l,  E,  o, -d, -w, \
    u,  w,  b, -s, -y, -d,  q,  A,  f, -o, -C, -h,  m,  E,  j, -k, -F, -l,  i,  D,  n, -g, -B, -p,  e,  z,  r, -c, -x, -t,  a,  v, \
    w,  s, -d, -A, -o,  h,  E,  k, -l, -D, -g,  p,  z,  c, -t, -v,  a,  x,  r, -e, -B, -n,  i,  F,  j, -m, -C, -f,  q,  y,  b, -u, \
    y,  o, -j, -D, -e,  t,  t, -e, -D, -j,  o,  y,  0, -y, -o,  j,  D,  e, -t, -t,  e,  D,  j, -o, -y,  0,  y,  o, -j, -D, -e,  t, \
    A,  k, -p, -v,  e,  F,  f, -u, -q,  j,  B,  a, -z, -l,  o,  w, -d, -E, -g,  t,  r, -i, -C, -b,  y,  m, -n, -x,  c,  D,  h, -s, \
    C,  g, -v, -n,  o,  u, -h, -B,  a,  D,  f, -w, -m,  p,  t, -i, -A,  b,  E,  e, -x, -l,  q,  s, -j, -z,  c,  F,  d, -y, -k,  r, \
    E,  c, -B, -f,  y,  i, -v, -l,  s,  o, -p, -r,  m,  u, -j, -x,  g,  A, -d, -D,  a,  F,  b, -C, -e,  z,  h, -w, -k,  t,  n, -q, \
    F, -a, -E,  b,  D, -c, -C,  d,  B, -e, -A,  f,  z, -g, -y,  h,  x, -i, -w,  j,  v, -k, -u,  l,  t, -m, -s,  n,  r, -o, -q,  p, \
    D, -e, -y,  j,  t, -o, -o,  t,  j, -y, -e,  D,  0, -D,  e,  y, -j, -t,  o,  o, -t, -j,  y,  e, -D,  0,  D, -e, -y,  j,  t, -o, \
    B, -i, -s,  r,  j, -A, -a,  C, -h, -t,  q,  k, -z, -b,  D, -g, -u,  p,  l, -y, -c,  E, -f, -v,  o,  m, -x, -d,  F, -e, -w,  n, \
    z, -m, -m,  z,  0, -z,  m,  m, -z,  0,  z, -m, -m,  z,  0, -z,  m,  m, -z,  0,  z, -m, -m,  z,  0, -z,  m,  m, -z,  0,  z, -m, \
    x, -q, -g,  E, -j, -n,  A, -c, -u,  t,  d, -B,  m,  k, -D,  f,  r, -w, -a,  y, -p, -h,  F, -i, -o,  z, -b, -v,  s,  e, -C,  l, \
    v, -u, -a,  w, -t, -b,  x, -s, -c,  y, -r, -d,  z, -q, -e,  A, -p, -f,  B, -o, -g,  C, -n, -h,  D, -m, -i,  E, -l, -j,  F, -k, \
    t, -y,  e,  o, -D,  j,  j, -D,  o,  e, -y,  t,  0, -t,  y, -e, -o,  D, -j, -j,  D, -o, -e,  y, -t,  0,  t, -y,  e,  o, -D,  j, \
    r, -C,  k,  g, -y,  v, -d, -n,  F, -o, -c,  u, -z,  h,  j, -B,  s, -a, -q,  D, -l, -f,  x, -w,  e,  m, -E,  p,  b, -t,  A, -i, \
    p, -F,  q, -a, -o,  E, -r,  b,  n, -D,  s, -c, -m,  C, -t,  d,  l, -B,  u, -e, -k,  A, -v,  f,  j, -z,  w, -g, -i,  y, -x,  h, \
    n, -B,  w, -i, -e,  s, -F,  r, -d, -j,  x, -A,  m,  a, -o,  C, -v,  h,  f, -t,  E, -q,  c,  k, -y,  z, -l, -b,  p, -D,  u, -g, \
    l, -x,  C, -q,  e,  g, -s,  E, -v,  j,  b, -n,  z, -A,  o, -c, -i,  u, -F,  t, -h, -d,  p, -B,  y, -m,  a,  k, -w,  D, -r,  f, \
    j, -t,  D, -y,  o, -e, -e,  o, -y,  D, -t,  j,  0, -j,  t, -D,  y, -o,  e,  e, -o,  y, -D,  t, -j,  0,  j, -t,  D, -y,  o, -e, \
    h, -p,  x, -F,  y, -q,  i, -a, -g,  o, -w,  E, -z,  r, -j,  b,  f, -n,  v, -D,  A, -s,  k, -c, -e,  m, -u,  C, -B,  t, -l,  d, \
    f, -l,  r, -x,  D, -C,  w, -q,  k, -e, -a,  g, -m,  s, -y,  E, -B,  v, -p,  j, -d, -b,  h, -n,  t, -z,  F, -A,  u, -o,  i, -c, \
    d, -h,  l, -p,  t, -x,  B, -F,  C, -y,  u, -q,  m, -i,  e, -a, -c,  g, -k,  o, -s,  w, -A,  E, -D,  z, -v,  r, -n,  j, -f,  b, \
    b, -d,  f, -h,  j, -l,  n, -p,  r, -t,  v, -x,  z, -B,  D, -F,  E, -C,  A, -y,  w, -u,  s, -q,  o, -m,  k, -i,  g, -e,  c, -a, \
}

// DCT-8
#define DEFINE_DCT8_P4_MATRIX(a,b,c,d) \
{ \
    a,  b,  c,  d, \
    b,  0, -b, -b, \
    c, -b, -d,  a, \
    d, -b,  a, -c, \
}

#define DEFINE_DCT8_P8_MATRIX(a,b,c,d,e,f,g,h) \
{ \
    a,  b,  c,  d,  e,  f,  g,  h, \
    b,  e,  h, -g, -d, -a, -c, -f, \
    c,  h, -e, -a, -f,  g,  b,  d, \
    d, -g, -a, -h,  c,  e, -f, -b, \
    e, -d, -f,  c,  g, -b, -h,  a, \
    f, -a,  g,  e, -b,  h,  d, -c, \
    g, -c,  b, -f, -h,  d, -a,  e, \
    h, -f,  d, -b,  a, -c,  e, -g, \
}

#define DEFINE_DCT8_P16_MATRIX(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) \
{ \
    a,  b,  c,  d,  e,  f,  g,  h,  i,  j,  k,  l,  m,  n,  o,  p, \
    b,  e,  h,  k,  n,  0, -n, -k, -h, -e, -b, -b, -e, -h, -k, -n, \
    c,  h,  m, -p, -k, -f, -a, -e, -j, -o,  n,  i,  d,  b,  g,  l, \
    d,  k, -p, -i, -b, -f, -m,  n,  g,  a,  h,  o, -l, -e, -c, -j, \
    e,  n, -k, -b, -h,  0,  h,  b,  k, -n, -e, -e, -n,  k,  b,  h, \
    f,  0, -f, -f,  0,  f,  f,  0, -f, -f,  0,  f,  f,  0, -f, -f, \
    g, -n, -a, -m,  h,  f, -o, -b, -l,  i,  e, -p, -c, -k,  j,  d, \
    h, -k, -e,  n,  b,  0, -b, -n,  e,  k, -h, -h,  k,  e, -n, -b, \
    i, -h, -j,  g,  k, -f, -l,  e,  m, -d, -n,  c,  o, -b, -p,  a, \
    j, -e, -o,  a, -n, -f,  i,  k, -d, -p,  b, -m, -g,  h,  l, -c, \
    k, -b,  n,  h, -e,  0,  e, -h, -n,  b, -k, -k,  b, -n, -h,  e, \
    l, -b,  i,  o, -e,  f, -p, -h,  c, -m, -k,  a, -j, -n,  d, -g, \
    m, -e,  d, -l, -n,  f, -c,  k,  o, -g,  b, -j, -p,  h, -a,  i, \
    n, -h,  b, -e,  k,  0, -k,  e, -b,  h, -n, -n,  h, -b,  e, -k, \
    o, -k,  g, -c,  b, -f,  j, -n, -p,  l, -h,  d, -a,  e, -i,  m, \
    p, -n,  l, -j,  h, -f,  d, -b,  a, -c,  e, -g,  i, -k,  m, -o, \
}

#define DEFINE_DCT8_P32_MATRIX(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F) \
{ \
    a,  b,  c,  d,  e,  f,  g,  h,  i,  j,  k,  l,  m,  n,  o,  p,  q,  r,  s,  t,  u,  v,  w,  x,  y,  z,  A,  B,  C,  D,  E,  F, \
    b,  e,  h,  k,  n,  q,  t,  w,  z,  C,  F, -E, -B, -y, -v, -s, -p, -m, -j, -g, -d, -a, -c, -f, -i, -l, -o, -r, -u, -x, -A, -D, \
    c,  h,  m,  r,  w,  B,  0, -B, -w, -r, -m, -h, -c, -c, -h, -m, -r, -w, -B,  0,  B,  w,  r,  m,  h,  c,  c,  h,  m,  r,  w,  B, \
    d,  k,  r,  y,  F, -A, -t, -m, -f, -b, -i, -p, -w, -D,  C,  v,  o,  h,  a,  g,  n,  u,  B, -E, -x, -q, -j, -c, -e, -l, -s, -z, \
    e,  n,  w,  F, -y, -p, -g, -c, -l, -u, -D,  A,  r,  i,  a,  j,  s,  B, -C, -t, -k, -b, -h, -q, -z,  E,  v,  m,  d,  f,  o,  x, \
    f,  q,  B, -A, -p, -e, -g, -r, -C,  z,  o,  d,  h,  s,  D, -y, -n, -c, -i, -t, -E,  x,  m,  b,  j,  u,  F, -w, -l, -a, -k, -v, \
    g,  t,  0, -t, -g, -g, -t,  0,  t,  g,  g,  t,  0, -t, -g, -g, -t,  0,  t,  g,  g,  t,  0, -t, -g, -g, -t,  0,  t,  g,  g,  t, \
    h,  w, -B, -m, -c, -r,  0,  r,  c,  m,  B, -w, -h, -h, -w,  B,  m,  c,  r,  0, -r, -c, -m, -B,  w,  h,  h,  w, -B, -m, -c, -r, \
    i,  z, -w, -f, -l, -C,  t,  c,  o,  F, -q, -a, -r,  E,  n,  d,  u, -B, -k, -g, -x,  y,  h,  j,  A, -v, -e, -m, -D,  s,  b,  p, \
    j,  C, -r, -b, -u,  z,  g,  m,  F, -o, -e, -x,  w,  d,  p, -E, -l, -h, -A,  t,  a,  s, -B, -i, -k, -D,  q,  c,  v, -y, -f, -n, \
    k,  F, -m, -i, -D,  o,  g,  B, -q, -e, -z,  s,  c,  x, -u, -a, -v,  w,  b,  t, -y, -d, -r,  A,  f,  p, -C, -h, -n,  E,  j,  l, \
    l, -E, -h, -p,  A,  d,  t, -w, -a, -x,  s,  e,  B, -o, -i, -F,  k,  m, -D, -g, -q,  z,  c,  u, -v, -b, -y,  r,  f,  C, -n, -j, \
    m, -B, -c, -w,  r,  h,  0, -h, -r,  w,  c,  B, -m, -m,  B,  c,  w, -r, -h,  0,  h,  r, -w, -c, -B,  m,  m, -B, -c, -w,  r,  h, \
    n, -y, -c, -D,  i,  s, -t, -h,  E,  d,  x, -o, -m,  z,  b,  C, -j, -r,  u,  g, -F, -e, -w,  p,  l, -A, -a, -B,  k,  q, -v, -f, \
    o, -v, -h,  C,  a,  D, -g, -w,  n,  p, -u, -i,  B,  b,  E, -f, -x,  m,  q, -t, -j,  A,  c,  F, -e, -y,  l,  r, -s, -k,  z,  d, \
    p, -s, -m,  v,  j, -y, -g,  B,  d, -E, -a, -F,  c,  C, -f, -z,  i,  w, -l, -t,  o,  q, -r, -n,  u,  k, -x, -h,  A,  e, -D, -b, \
    q, -p, -r,  o,  s, -n, -t,  m,  u, -l, -v,  k,  w, -j, -x,  i,  y, -h, -z,  g,  A, -f, -B,  e,  C, -d, -D,  c,  E, -b, -F,  a, \
    r, -m, -w,  h,  B, -c,  0,  c, -B, -h,  w,  m, -r, -r,  m,  w, -h, -B,  c,  0, -c,  B,  h, -w, -m,  r,  r, -m, -w,  h,  B, -c, \
    s, -j, -B,  a, -C, -i,  t,  r, -k, -A,  b, -D, -h,  u,  q, -l, -z,  c, -E, -g,  v,  p, -m, -y,  d, -F, -f,  w,  o, -n, -x,  e, \
    t, -g,  0,  g, -t, -t,  g,  0, -g,  t,  t, -g,  0,  g, -t, -t,  g,  0, -g,  t,  t, -g,  0,  g, -t, -t,  g,  0, -g,  t,  t, -g, \
    u, -d,  B,  n, -k, -E,  g, -r, -x,  a, -y, -q,  h, -F, -j,  o,  A, -c,  v,  t, -e,  C,  m, -l, -D,  f, -s, -w,  b, -z, -p,  i, \
    v, -a,  w,  u, -b,  x,  t, -c,  y,  s, -d,  z,  r, -e,  A,  q, -f,  B,  p, -g,  C,  o, -h,  D,  n, -i,  E,  m, -j,  F,  l, -k, \
    w, -c,  r,  B, -h,  m,  0, -m,  h, -B, -r,  c, -w, -w,  c, -r, -B,  h, -m,  0,  m, -h,  B,  r, -c,  w,  w, -c,  r,  B, -h,  m, \
    x, -f,  m, -E, -q,  b, -t, -B,  j, -i,  A,  u, -c,  p,  F, -n,  e, -w, -y,  g, -l,  D,  r, -a,  s,  C, -k,  h, -z, -v,  d, -o, \
    y, -i,  h, -x, -z,  j, -g,  w,  A, -k,  f, -v, -B,  l, -e,  u,  C, -m,  d, -t, -D,  n, -c,  s,  E, -o,  b, -r, -F,  p, -a,  q, \
    z, -l,  c, -q,  E,  u, -g,  h, -v, -D,  p, -b,  m, -A, -y,  k, -d,  r, -F, -t,  f, -i,  w,  C, -o,  a, -n,  B,  x, -j,  e, -s, \
    A, -o,  c, -j,  v,  F, -t,  h, -e,  q, -C, -y,  m, -a,  l, -x, -D,  r, -f,  g, -s,  E,  w, -k,  b, -n,  z,  B, -p,  d, -i,  u, \
    B, -r,  h, -c,  m, -w,  0,  w, -m,  c, -h,  r, -B, -B,  r, -h,  c, -m,  w,  0, -w,  m, -c,  h, -r,  B,  B, -r,  h, -c,  m, -w, \
    C, -u,  m, -e,  d, -l,  t, -B, -D,  v, -n,  f, -c,  k, -s,  A,  E, -w,  o, -g,  b, -j,  r, -z, -F,  x, -p,  h, -a,  i, -q,  y, \
    D, -x,  r, -l,  f, -a,  g, -m,  s, -y,  E,  C, -w,  q, -k,  e, -b,  h, -n,  t, -z,  F,  B, -v,  p, -j,  d, -c,  i, -o,  u, -A, \
    E, -A,  w, -s,  o, -k,  g, -c,  b, -f,  j, -n,  r, -v,  z, -D, -F,  B, -x,  t, -p,  l, -h,  d, -a,  e, -i,  m, -q,  u, -y,  C, \
    F, -D,  B, -z,  x, -v,  t, -r,  p, -n,  l, -j,  h, -f,  d, -b,  a, -c,  e, -g,  i, -k,  m, -o,  q, -s,  u, -w,  y, -A,  C, -E, \
}

// DCT-2
const int16_t uvg_g_DCT2P2[4] = DEFINE_DCT2_P2_MATRIX(64);
const int16_t uvg_g_DCT2P4[16] = DEFINE_DCT2_P4_MATRIX(64, 83, 36);
const int16_t uvg_g_DCT2P8[64] = DEFINE_DCT2_P8_MATRIX(64, 83, 36, 89, 75, 50, 18);
const int16_t uvg_g_DCT2P16[256] = DEFINE_DCT2_P16_MATRIX(64, 83, 36, 89, 75, 50, 18, 90, 87, 80, 70, 57, 43, 25, 9);
const int16_t uvg_g_DCT2P32[1024] = DEFINE_DCT2_P32_MATRIX(64, 83, 36, 89, 75, 50, 18, 90, 87, 80, 70, 57, 43, 25, 9, 90, 90, 88, 85, 82, 78, 73, 67, 61, 54, 46, 38, 31, 22, 13, 4);

// DST-7
const int16_t uvg_g_DST7P4[16] = DEFINE_DST7_P4_MATRIX(29, 55, 74, 84);
const int16_t uvg_g_DST7P8[64] = DEFINE_DST7_P8_MATRIX(17, 32, 46, 60, 71, 78, 85, 86);
const int16_t uvg_g_DST7P16[256] = DEFINE_DST7_P16_MATRIX(8, 17, 25, 33, 40, 48, 55, 62, 68, 73, 77, 81, 85, 87, 88, 88);
const int16_t uvg_g_DST7P32[1024] = DEFINE_DST7_P32_MATRIX(4, 9, 13, 17, 21, 26, 30, 34, 38, 42, 46, 50, 53, 56, 60, 63, 66, 68, 72, 74, 77, 78, 80, 82, 84, 85, 86, 87, 88, 89, 90, 90);

// DCT-8
const int16_t uvg_g_DCT8P4[64] = DEFINE_DCT8_P4_MATRIX(84, 74, 55, 29);
const int16_t uvg_g_DCT8P8[256] = DEFINE_DCT8_P8_MATRIX(86, 85, 78, 71, 60, 46, 32, 17);
const int16_t uvg_g_DCT8P16[256] = DEFINE_DCT8_P16_MATRIX(88, 88, 87, 85, 81, 77, 73, 68, 62, 55, 48, 40, 33, 25, 17, 8);
const int16_t uvg_g_DCT8P32[1024] = DEFINE_DCT8_P32_MATRIX(90, 90, 89, 88, 87, 86, 85, 84, 82, 80, 78, 77, 74, 72, 68, 66, 63, 60, 56, 53, 50, 46, 42, 38, 34, 30, 26, 21, 17, 13, 9, 4);

// ********************************** DCT-2 **********************************
static void fastForwardDCT2_B2(const int16_t* src, int16_t* dst, int32_t shift, int line, int skip_line, int skip_line2)
{
  int32_t j;
  int32_t E, O;
  int32_t add = (shift > 0) ? (1 << (shift - 1)) : 0;

  const int16_t* iT = uvg_g_DCT2P2;

  int16_t *p_coef = dst;
  const int  reduced_line = line - skip_line;
  for (j = 0; j < reduced_line; j++)
  {
    /* E and O */
    E = src[0] + src[1];
    O = src[0] - src[1];

    dst[0] = (iT[0] * E + add) >> shift;
    dst[line] = (iT[2] * O + add) >> shift;


    src += 2;
    dst++;
  }
  if (skip_line)
  {
    dst = p_coef + reduced_line;
    for (j = 0; j < 2; j++)
    {
      memset(dst, 0, sizeof(int16_t) * skip_line);
      dst += line;
    }
  }
}

static void fastInverseDCT2_B2(const int16_t* src, int16_t* dst, int shift, int line, int skip_line, int skip_line2)
{
  int32_t j;
  int32_t E, O;
  int32_t add = 1 << (shift - 1);

  const int16_t* iT = uvg_g_DCT2P2;

  const int  reduced_line = line - skip_line;
  for (j = 0; j < reduced_line; j++)
  {
    /* Utilizing symmetry properties to the maximum to minimize the number of multiplications */
    E = iT[0] * (src[0] + src[line]);
    O = iT[2] * (src[0] - src[line]);

    /* Combining even and odd terms at each hierarchy levels to calculate the final spatial domain vector */
    dst[0] = (short)CLIP(-32768, 32767, (E + add) >> shift);
    dst[1] = (short)CLIP(-32768, 32767, (O + add) >> shift);

    src++;
    dst += 2;
  }
  if (skip_line)
  {
    memset(dst, 0, (skip_line << 1) * sizeof(int16_t));
  }
}

static void fastForwardDCT2_B4(const int16_t* src, int16_t* dst, int32_t shift, int line, int skip_line, int skip_line2)
{
  int32_t j;
  int32_t E[2], O[2];
  int32_t add = (shift > 0) ? (1 << (shift - 1)) : 0;
  const int16_t *iT = uvg_g_DCT2P4;

  int16_t *p_coef = dst;
  const int  reduced_line = line - skip_line;
  for (j = 0; j < reduced_line; j++)
  {
    /* E and O */
    E[0] = src[0] + src[3];
    O[0] = src[0] - src[3];
    E[1] = src[1] + src[2];
    O[1] = src[1] - src[2];

    dst[0] = (iT[0] * E[0] + iT[1] * E[1] + add) >> shift;
    dst[2 * line] = (iT[8] * E[0] + iT[9] * E[1] + add) >> shift;
    dst[line] = (iT[4] * O[0] + iT[5] * O[1] + add) >> shift;
    dst[3 * line] = (iT[12] * O[0] + iT[13] * O[1] + add) >> shift;

    src += 4;
    dst++;
  }
  if (skip_line)
  {
    dst = p_coef + reduced_line;
    for (j = 0; j < 4; j++)
    {
      memset(dst, 0, sizeof(int16_t)*skip_line);
      dst += line;
    }
  }
}

static void fastInverseDCT2_B4(const int16_t* src, int16_t* dst, int32_t shift, int line, int skip_line, int skip_line2)
{
  int32_t j;
  int32_t E[2], O[2];
  int32_t add = 1 << (shift - 1);
  const int16_t *iT = uvg_g_DCT2P4;
  const int  reduced_line = line - skip_line;

  for (j = 0; j < reduced_line; j++)
  {
    /* Utilizing symmetry properties to the maximum to minimize the number of multiplications */
    O[0] = iT[1 * 4 + 0] * src[line] + iT[3 * 4 + 0] * src[3 * line];
    O[1] = iT[1 * 4 + 1] * src[line] + iT[3 * 4 + 1] * src[3 * line];
    E[0] = iT[0 * 4 + 0] * src[0] + iT[2 * 4 + 0] * src[2 * line];
    E[1] = iT[0 * 4 + 1] * src[0] + iT[2 * 4 + 1] * src[2 * line];

    /* Combining even and odd terms at each hierarchy levels to calculate the final spatial domain vector */
    dst[0] = (short)CLIP(-32768, 32767, (E[0] + O[0] + add) >> shift);
    dst[1] = (short)CLIP(-32768, 32767, (E[1] + O[1] + add) >> shift);
    dst[2] = (short)CLIP(-32768, 32767, (E[1] - O[1] + add) >> shift);
    dst[3] = (short)CLIP(-32768, 32767, (E[0] - O[0] + add) >> shift);

    src++;
    dst += 4;
  }
  if (skip_line)
  {
    memset(dst, 0, (skip_line << 2) * sizeof(int16_t));
  }
}

static void fastForwardDCT2_B8(const int16_t* src, int16_t* dst, int32_t shift, int line, int skip_line, int skip_line2)
{
  int32_t j, k;
  int32_t E[4], O[4];
  int32_t EE[2], EO[2];
  int32_t add = (shift > 0) ? (1 << (shift - 1)) : 0;
  const int16_t *iT = uvg_g_DCT2P8;

  int16_t *p_coef = dst;
  const int  reduced_line = line - skip_line;
  for (j = 0; j < reduced_line; j++)
  {
    /* E and O*/
    for (k = 0; k < 4; k++)
    {
      E[k] = src[k] + src[7 - k];
      O[k] = src[k] - src[7 - k];
    }
    /* EE and EO */
    EE[0] = E[0] + E[3];
    EO[0] = E[0] - E[3];
    EE[1] = E[1] + E[2];
    EO[1] = E[1] - E[2];

    dst[0] = (iT[0] * EE[0] + iT[1] * EE[1] + add) >> shift;
    dst[4 * line] = (iT[32] * EE[0] + iT[33] * EE[1] + add) >> shift;
    dst[2 * line] = (iT[16] * EO[0] + iT[17] * EO[1] + add) >> shift;
    dst[6 * line] = (iT[48] * EO[0] + iT[49] * EO[1] + add) >> shift;

    dst[line] = (iT[8] * O[0] + iT[9] * O[1] + iT[10] * O[2] + iT[11] * O[3] + add) >> shift;
    dst[3 * line] = (iT[24] * O[0] + iT[25] * O[1] + iT[26] * O[2] + iT[27] * O[3] + add) >> shift;
    dst[5 * line] = (iT[40] * O[0] + iT[41] * O[1] + iT[42] * O[2] + iT[43] * O[3] + add) >> shift;
    dst[7 * line] = (iT[56] * O[0] + iT[57] * O[1] + iT[58] * O[2] + iT[59] * O[3] + add) >> shift;

    src += 8;
    dst++;
  }
  if (skip_line)
  {
    dst = p_coef + reduced_line;
    for (j = 0; j < 8; j++)
    {
      memset(dst, 0, sizeof(int16_t)*skip_line);
      dst += line;
    }
  }
}

static void fastInverseDCT2_B8(const int16_t* src, int16_t* dst, int32_t shift, int line, int skip_line, int skip_line2)
{
  int32_t j, k;
  int32_t E[4], O[4];
  int32_t EE[2], EO[2];
  int32_t add = 1 << (shift - 1);

  const int16_t *iT = uvg_g_DCT2P8;

  const int  reduced_line = line - skip_line;
  for (j = 0; j < reduced_line; j++)
  {
    /* Utilizing symmetry properties to the maximum to minimize the number of multiplications */
    for (k = 0; k < 4; k++)
    {
      O[k] = iT[1 * 8 + k] * src[line] + iT[3 * 8 + k] * src[3 * line] + iT[5 * 8 + k] * src[5 * line] + iT[7 * 8 + k] * src[7 * line];
    }

    EO[0] = iT[2 * 8 + 0] * src[2 * line] + iT[6 * 8 + 0] * src[6 * line];
    EO[1] = iT[2 * 8 + 1] * src[2 * line] + iT[6 * 8 + 1] * src[6 * line];
    EE[0] = iT[0 * 8 + 0] * src[0] + iT[4 * 8 + 0] * src[4 * line];
    EE[1] = iT[0 * 8 + 1] * src[0] + iT[4 * 8 + 1] * src[4 * line];

    /* Combining even and odd terms at each hierarchy levels to calculate the final spatial domain vector */
    E[0] = EE[0] + EO[0];
    E[3] = EE[0] - EO[0];
    E[1] = EE[1] + EO[1];
    E[2] = EE[1] - EO[1];

    for (k = 0; k < 4; k++)
    {
      dst[k] = (short)CLIP(-32768, 32767, (E[k] + O[k] + add) >> shift);
      dst[k + 4] = (short)CLIP(-32768, 32767, (E[3 - k] - O[3 - k] + add) >> shift);
    }
    src++;
    dst += 8;
  }
  if (skip_line)
  {
    memset(dst, 0, (skip_line << 3) * sizeof(int16_t));
  }
}

static void fastForwardDCT2_B16(const int16_t* src, int16_t* dst, int32_t shift, int line, int skip_line, int skip_line2)
{
  int32_t j, k;
  int32_t E[8], O[8];
  int32_t EE[4], EO[4];
  int32_t EEE[2], EEO[2];
  int32_t add = (shift > 0) ? (1 << (shift - 1)) : 0;

  const int16_t *iT = uvg_g_DCT2P16;

  int16_t *p_coef = dst;
  const int  reduced_line = line - skip_line;
  for (j = 0; j < reduced_line; j++)
  {
    /* E and O*/
    for (k = 0; k < 8; k++)
    {
      E[k] = src[k] + src[15 - k];
      O[k] = src[k] - src[15 - k];
    }
    /* EE and EO */
    for (k = 0; k < 4; k++)
    {
      EE[k] = E[k] + E[7 - k];
      EO[k] = E[k] - E[7 - k];
    }
    /* EEE and EEO */
    EEE[0] = EE[0] + EE[3];
    EEO[0] = EE[0] - EE[3];
    EEE[1] = EE[1] + EE[2];
    EEO[1] = EE[1] - EE[2];

    dst[0] = (iT[0] * EEE[0] + iT[1] * EEE[1] + add) >> shift;
    dst[8 * line] = (iT[8 * 16] * EEE[0] + iT[8 * 16 + 1] * EEE[1] + add) >> shift;
    dst[4 * line] = (iT[4 * 16] * EEO[0] + iT[4 * 16 + 1] * EEO[1] + add) >> shift;
    dst[12 * line] = (iT[12 * 16] * EEO[0] + iT[12 * 16 + 1] * EEO[1] + add) >> shift;

    for (k = 2; k < 16; k += 4)
    {
      dst[k*line] = (iT[k * 16] * EO[0] + iT[k * 16 + 1] * EO[1] + iT[k * 16 + 2] * EO[2] + iT[k * 16 + 3] * EO[3] + add) >> shift;
    }

    for (k = 1; k < 16; k += 2)
    {
      dst[k*line] = (iT[k * 16] * O[0] + iT[k * 16 + 1] * O[1] + iT[k * 16 + 2] * O[2] + iT[k * 16 + 3] * O[3] +
        iT[k * 16 + 4] * O[4] + iT[k * 16 + 5] * O[5] + iT[k * 16 + 6] * O[6] + iT[k * 16 + 7] * O[7] + add) >> shift;
    }

    src += 16;
    dst++;

  }
  if (skip_line)
  {
    dst = p_coef + reduced_line;
    for (j = 0; j < 16; j++)
    {
      memset(dst, 0, sizeof(int16_t)*skip_line);
      dst += line;
    }
  }
}

static void fastInverseDCT2_B16(const int16_t* src, int16_t* dst, int32_t shift, int line, int skip_line, int skip_line2)
{
  int32_t j, k;
  int32_t E[8], O[8];
  int32_t EE[4], EO[4];
  int32_t EEE[2], EEO[2];
  int32_t add = 1 << (shift - 1);

  const int16_t *iT = uvg_g_DCT2P16;

  const int  reduced_line = line - skip_line;

  for (j = 0; j < reduced_line; j++)
  {
    /* Utilizing symmetry properties to the maximum to minimize the number of multiplications */
    for (k = 0; k < 8; k++)
    {
      O[k] = iT[1 * 16 + k] * src[line] + iT[3 * 16 + k] * src[3 * line] + iT[5 * 16 + k] * src[5 * line] + iT[7 * 16 + k] * src[7 * line] +
        iT[9 * 16 + k] * src[9 * line] + iT[11 * 16 + k] * src[11 * line] + iT[13 * 16 + k] * src[13 * line] + iT[15 * 16 + k] * src[15 * line];
    }
    for (k = 0; k < 4; k++)
    {
      EO[k] = iT[2 * 16 + k] * src[2 * line] + iT[6 * 16 + k] * src[6 * line] + iT[10 * 16 + k] * src[10 * line] + iT[14 * 16 + k] * src[14 * line];
    }
    EEO[0] = iT[4 * 16] * src[4 * line] + iT[12 * 16] * src[12 * line];
    EEE[0] = iT[0] * src[0] + iT[8 * 16] * src[8 * line];
    EEO[1] = iT[4 * 16 + 1] * src[4 * line] + iT[12 * 16 + 1] * src[12 * line];
    EEE[1] = iT[0 * 16 + 1] * src[0] + iT[8 * 16 + 1] * src[8 * line];

    /* Combining even and odd terms at each hierarchy levels to calculate the final spatial domain vector */
    for (k = 0; k < 2; k++)
    {
      EE[k] = EEE[k] + EEO[k];
      EE[k + 2] = EEE[1 - k] - EEO[1 - k];
    }
    for (k = 0; k < 4; k++)
    {
      E[k] = EE[k] + EO[k];
      E[k + 4] = EE[3 - k] - EO[3 - k];
    }
    for (k = 0; k < 8; k++)
    {
      dst[k] = (short)CLIP(-32768, 32767, (E[k] + O[k] + add) >> shift);
      dst[k + 8] = (short)CLIP(-32768, 32767, (E[7 - k] - O[7 - k] + add) >> shift);
    }
    src++;
    dst += 16;
  }
  if (skip_line)
  {
    memset(dst, 0, (skip_line << 4) * sizeof(int16_t));
  }
}

static void fastForwardDCT2_B32(const int16_t* src, int16_t* dst, int32_t shift, int line, int skip_line, int skip_line2)
{
  int32_t j, k;
  int32_t E[16], O[16];
  int32_t EE[8], EO[8];
  int32_t EEE[4], EEO[4];
  int32_t EEEE[2], EEEO[2];
  int32_t add = (shift > 0) ? (1 << (shift - 1)) : 0;

  const int16_t *iT = uvg_g_DCT2P32;

  int16_t *p_coef = dst;
  const int  reduced_line = line - skip_line;
  for (j = 0; j < reduced_line; j++)
  {
    /* E and O*/
    for (k = 0; k < 16; k++)
    {
      E[k] = src[k] + src[31 - k];
      O[k] = src[k] - src[31 - k];
    }
    /* EE and EO */
    for (k = 0; k < 8; k++)
    {
      EE[k] = E[k] + E[15 - k];
      EO[k] = E[k] - E[15 - k];
    }
    /* EEE and EEO */
    for (k = 0; k < 4; k++)
    {
      EEE[k] = EE[k] + EE[7 - k];
      EEO[k] = EE[k] - EE[7 - k];
    }
    /* EEEE and EEEO */
    EEEE[0] = EEE[0] + EEE[3];
    EEEO[0] = EEE[0] - EEE[3];
    EEEE[1] = EEE[1] + EEE[2];
    EEEO[1] = EEE[1] - EEE[2];

    dst[0] = (iT[0 * 32 + 0] * EEEE[0] + iT[0 * 32 + 1] * EEEE[1] + add) >> shift;
    dst[16 * line] = (iT[16 * 32 + 0] * EEEE[0] + iT[16 * 32 + 1] * EEEE[1] + add) >> shift;
    dst[8 * line] = (iT[8 * 32 + 0] * EEEO[0] + iT[8 * 32 + 1] * EEEO[1] + add) >> shift;
    dst[24 * line] = (iT[24 * 32 + 0] * EEEO[0] + iT[24 * 32 + 1] * EEEO[1] + add) >> shift;
    for (k = 4; k < 32; k += 8)
    {
      dst[k*line] = (iT[k * 32 + 0] * EEO[0] + iT[k * 32 + 1] * EEO[1] + iT[k * 32 + 2] * EEO[2] + iT[k * 32 + 3] * EEO[3] + add) >> shift;
    }
    for (k = 2; k < 32; k += 4)
    {
      dst[k*line] = (iT[k * 32 + 0] * EO[0] + iT[k * 32 + 1] * EO[1] + iT[k * 32 + 2] * EO[2] + iT[k * 32 + 3] * EO[3] +
        iT[k * 32 + 4] * EO[4] + iT[k * 32 + 5] * EO[5] + iT[k * 32 + 6] * EO[6] + iT[k * 32 + 7] * EO[7] + add) >> shift;
    }
    for (k = 1; k < 32; k += 2)
    {
      dst[k*line] = (iT[k * 32 + 0] * O[0] + iT[k * 32 + 1] * O[1] + iT[k * 32 + 2] * O[2] + iT[k * 32 + 3] * O[3] +
        iT[k * 32 + 4] * O[4] + iT[k * 32 + 5] * O[5] + iT[k * 32 + 6] * O[6] + iT[k * 32 + 7] * O[7] +
        iT[k * 32 + 8] * O[8] + iT[k * 32 + 9] * O[9] + iT[k * 32 + 10] * O[10] + iT[k * 32 + 11] * O[11] +
        iT[k * 32 + 12] * O[12] + iT[k * 32 + 13] * O[13] + iT[k * 32 + 14] * O[14] + iT[k * 32 + 15] * O[15] + add) >> shift;
    }
    src += 32;
    dst++;
  }
  if (skip_line)
  {
    dst = p_coef + reduced_line;
    for (j = 0; j < 32; j++)
    {
      memset(dst, 0, sizeof(int16_t)*skip_line);
      dst += line;
    }
  }
}

static void fastInverseDCT2_B32(const int16_t* src, int16_t* dst, int32_t shift, int line, int skip_line, int skip_line2)
{
  int32_t j, k;
  int32_t E[16], O[16];
  int32_t EE[8], EO[8];
  int32_t EEE[4], EEO[4];
  int32_t EEEE[2], EEEO[2];
  int32_t add = 1 << (shift - 1);

  const int16_t *iT = uvg_g_DCT2P32;

  const int  reduced_line = line - skip_line;
  for (j = 0; j < reduced_line; j++)
  {
    /* Utilizing symmetry properties to the maximum to minimize the number of multiplications */
    for (k = 0; k < 16; k++)
    {
      O[k] = iT[1 * 32 + k] * src[line] + iT[3 * 32 + k] * src[3 * line] + iT[5 * 32 + k] * src[5 * line] + iT[7 * 32 + k] * src[7 * line] +
        iT[9 * 32 + k] * src[9 * line] + iT[11 * 32 + k] * src[11 * line] + iT[13 * 32 + k] * src[13 * line] + iT[15 * 32 + k] * src[15 * line] +
        iT[17 * 32 + k] * src[17 * line] + iT[19 * 32 + k] * src[19 * line] + iT[21 * 32 + k] * src[21 * line] + iT[23 * 32 + k] * src[23 * line] +
        iT[25 * 32 + k] * src[25 * line] + iT[27 * 32 + k] * src[27 * line] + iT[29 * 32 + k] * src[29 * line] + iT[31 * 32 + k] * src[31 * line];
    }
    for (k = 0; k < 8; k++)
    {
      EO[k] = iT[2 * 32 + k] * src[2 * line] + iT[6 * 32 + k] * src[6 * line] + iT[10 * 32 + k] * src[10 * line] + iT[14 * 32 + k] * src[14 * line] +
        iT[18 * 32 + k] * src[18 * line] + iT[22 * 32 + k] * src[22 * line] + iT[26 * 32 + k] * src[26 * line] + iT[30 * 32 + k] * src[30 * line];
    }
    for (k = 0; k < 4; k++)
    {
      EEO[k] = iT[4 * 32 + k] * src[4 * line] + iT[12 * 32 + k] * src[12 * line] + iT[20 * 32 + k] * src[20 * line] + iT[28 * 32 + k] * src[28 * line];
    }
    EEEO[0] = iT[8 * 32 + 0] * src[8 * line] + iT[24 * 32 + 0] * src[24 * line];
    EEEO[1] = iT[8 * 32 + 1] * src[8 * line] + iT[24 * 32 + 1] * src[24 * line];
    EEEE[0] = iT[0 * 32 + 0] * src[0] + iT[16 * 32 + 0] * src[16 * line];
    EEEE[1] = iT[0 * 32 + 1] * src[0] + iT[16 * 32 + 1] * src[16 * line];

    /* Combining even and odd terms at each hierarchy levels to calculate the final spatial domain vector */
    EEE[0] = EEEE[0] + EEEO[0];
    EEE[3] = EEEE[0] - EEEO[0];
    EEE[1] = EEEE[1] + EEEO[1];
    EEE[2] = EEEE[1] - EEEO[1];
    for (k = 0; k < 4; k++)
    {
      EE[k] = EEE[k] + EEO[k];
      EE[k + 4] = EEE[3 - k] - EEO[3 - k];
    }
    for (k = 0; k < 8; k++)
    {
      E[k] = EE[k] + EO[k];
      E[k + 8] = EE[7 - k] - EO[7 - k];
    }
    for (k = 0; k < 16; k++)
    {
      dst[k] = (short)CLIP(-32768, 32767, (E[k] + O[k] + add) >> shift);
      dst[k + 16] = (short)CLIP(-32768, 32767, (E[15 - k] - O[15 - k] + add) >> shift);
    }
    src++;
    dst += 32;
  }
  if (skip_line)
  {
    memset(dst, 0, (skip_line << 5) * sizeof(int16_t));
  }
}

// ********************************** DST-7 **********************************
static void fastForwardDST7_B4(const int16_t* src, int16_t* dst, int32_t shift, int line, int skip_line, int skip_line2)
{
  int i;
  int32_t rnd_factor = (shift > 0) ? (1 << (shift - 1)) : 0;

  const int16_t *iT = uvg_g_DST7P4;

  int32_t c[4];
  int16_t *pCoeff = dst;
  const int  reduced_line = line - skip_line;
  for (i = 0; i < reduced_line; i++)
  {
    // Intermediate Variables
    c[0] = src[0] + src[3];
    c[1] = src[1] + src[3];
    c[2] = src[0] - src[1];
    c[3] = iT[2] * src[2];

    dst[0 * line] = (iT[0] * c[0] + iT[1] * c[1] + c[3] + rnd_factor) >> shift;
    dst[1 * line] = (iT[2] * (src[0] + src[1] - src[3]) + rnd_factor) >> shift;
    dst[2 * line] = (iT[0] * c[2] + iT[1] * c[0] - c[3] + rnd_factor) >> shift;
    dst[3 * line] = (iT[1] * c[2] - iT[0] * c[1] + c[3] + rnd_factor) >> shift;

    src += 4;
    dst++;
  }
  if (skip_line)
  {
    dst = pCoeff + reduced_line;
    for (i = 0; i < 4; i++)
    {
      memset(dst, 0, sizeof(int16_t)*skip_line);
      dst += line;
    }
  }
}

static void fastInverseDST7_B4(const int16_t* src, int16_t* dst, int32_t shift, int line, int skip_line, int skip_line2)
{
  int i;
  int32_t c[4];
  int32_t rnd_factor = (shift > 0) ? (1 << (shift - 1)) : 0;

  const int16_t *iT = uvg_g_DST7P4;

  const int  reduced_line = line - skip_line;
  for (i = 0; i < reduced_line; i++)
  {
    // Intermediate Variables
    c[0] = src[0 * line] + src[2 * line];
    c[1] = src[2 * line] + src[3 * line];
    c[2] = src[0 * line] - src[3 * line];
    c[3] = iT[2] * src[1 * line];

    dst[0] = (short)CLIP(-32768, 32767, (iT[0] * c[0] + iT[1] * c[1] + c[3] + rnd_factor) >> shift);
    dst[1] = (short)CLIP(-32768, 32767, (iT[1] * c[2] - iT[0] * c[1] + c[3] + rnd_factor) >> shift);
    dst[2] = (short)CLIP(-32768, 32767, (iT[2] * (src[0 * line] - src[2 * line] + src[3 * line]) + rnd_factor) >> shift);
    dst[3] = (short)CLIP(-32768, 32767, (iT[1] * c[0] + iT[0] * c[2] - c[3] + rnd_factor) >> shift);

    dst += 4;
    src++;
  }
  if (skip_line)
  {
    memset(dst, 0, (skip_line << 2) * sizeof(int16_t));
  }
}

static void fastForwardDST7_B16(const int16_t *src, int16_t *dst, int32_t shift, int line, int skip_line, int skip_line2)
{
  int j, k;
  int32_t a[5], b[5], c[5], d[5], t;
  int32_t add = (shift > 0) ? (1 << (shift - 1)) : 0;

  const int16_t *iT = uvg_g_DST7P16;

  int16_t *p_coef = dst;
  const int  reduced_line = line - skip_line;
  const int  cutoff = 16 - skip_line2;

  for (j = 0; j < reduced_line; j++)
  {
    for (k = 0; k < 5; k++)
    {
      a[k] = src[k] + src[11 + k];
      b[k] = src[9 - k] + src[11 + k];
      c[k] = src[k] - src[9 - k];
      d[k] = src[k] + src[9 - k] - src[11 + k];
    }

    t = iT[10] * src[10];

    dst[1 * line] = (iT[2] * d[0] + iT[5] * d[1] + iT[8] * d[2] + iT[11] * d[3] + iT[14] * d[4] + add) >> shift;
    dst[4 * line] = (iT[8] * d[0] + iT[14] * d[1] + iT[5] * d[2] - iT[2] * d[3] - iT[11] * d[4] + add) >> shift;
    dst[7 * line] = (iT[14] * d[0] + iT[2] * d[1] - iT[11] * d[2] - iT[5] * d[3] + iT[8] * d[4] + add) >> shift;
    dst[10 * line] = (iT[11] * d[0] - iT[8] * d[1] - iT[2] * d[2] + iT[14] * d[3] - iT[5] * d[4] + add) >> shift;
    dst[13 * line] = (iT[5] * d[0] - iT[11] * d[1] + iT[14] * d[2] - iT[8] * d[3] + iT[2] * d[4] + add) >> shift;

    dst[5 * line] = (iT[10] * (src[0] + src[1] - src[3] - src[4] + src[6] + src[7] - src[9] - src[10] + src[12] + src[13] - src[15]) + add) >> shift;

    dst[0 * line] = (iT[0] * a[0] + iT[9] * b[0] + iT[1] * a[1] + iT[8] * b[1] + iT[2] * a[2] + iT[7] * b[2] + iT[3] * a[3] + iT[6] * b[3] + iT[4] * a[4] + iT[5] * b[4] + t + add) >> shift;
    dst[2 * line] = (iT[4] * c[0] - iT[5] * b[0] + iT[9] * c[1] - iT[0] * b[1] + iT[6] * c[2] + iT[3] * a[2] + iT[1] * c[3] + iT[8] * a[3] + iT[7] * a[4] + iT[2] * b[4] - t + add) >> shift;
    dst[3 * line] = (iT[6] * a[0] + iT[3] * b[0] + iT[2] * c[1] + iT[7] * a[1] + iT[9] * c[2] + iT[0] * a[2] + iT[4] * c[3] - iT[5] * b[3] - iT[1] * a[4] - iT[8] * b[4] + t + add) >> shift;
    dst[6 * line] = (iT[8] * a[0] + iT[1] * c[0] + iT[6] * c[1] - iT[3] * b[1] - iT[5] * a[2] - iT[4] * b[2] - iT[7] * c[3] - iT[2] * a[3] - iT[0] * c[4] + iT[9] * b[4] + t + add) >> shift;
    dst[8 * line] = (iT[4] * c[0] + iT[5] * a[0] - iT[0] * c[1] + iT[9] * b[1] - iT[3] * c[2] - iT[6] * a[2] + iT[1] * c[3] - iT[8] * b[3] + iT[2] * c[4] + iT[7] * a[4] - t + add) >> shift;
    dst[9 * line] = (iT[7] * c[0] + iT[2] * a[0] - iT[4] * a[1] - iT[5] * b[1] - iT[8] * c[2] + iT[1] * b[2] + iT[9] * a[3] + iT[0] * b[3] + iT[3] * c[4] - iT[6] * b[4] + t + add) >> shift;
    dst[11 * line] = (iT[9] * a[0] + iT[0] * b[0] - iT[8] * c[1] - iT[1] * a[1] + iT[2] * c[2] - iT[7] * b[2] + iT[6] * a[3] + iT[3] * b[3] - iT[5] * c[4] - iT[4] * a[4] - t + add) >> shift;
    dst[12 * line] = (iT[7] * c[0] - iT[2] * b[0] - iT[5] * c[1] - iT[4] * a[1] + iT[8] * a[2] + iT[1] * b[2] - iT[0] * a[3] - iT[9] * b[3] - iT[6] * c[4] + iT[3] * b[4] + t + add) >> shift;
    dst[14 * line] = (iT[3] * a[0] + iT[6] * b[0] - iT[7] * a[1] - iT[2] * b[1] + iT[0] * c[2] + iT[9] * a[2] - iT[4] * c[3] - iT[5] * a[3] + iT[8] * c[4] + iT[1] * a[4] - t + add) >> shift;
    dst[15 * line] = (iT[1] * c[0] - iT[8] * b[0] - iT[3] * c[1] + iT[6] * b[1] + iT[5] * c[2] - iT[4] * b[2] - iT[7] * c[3] + iT[2] * b[3] + iT[9] * c[4] - iT[0] * b[4] + t + add) >> shift;

    src += 16;
    dst++;
  }

  if (skip_line)
  {
    dst = p_coef + reduced_line;
    for (j = 0; j < cutoff; j++)
    {
      memset(dst, 0, sizeof(int16_t)*skip_line);
      dst += line;
    }
  }

  if (skip_line2)
  {
    dst = p_coef + line * cutoff;
    memset(dst, 0, sizeof(int16_t) * line * skip_line2);
  }
}

static void fastInverseDST7_B16(const int16_t *src, int16_t *dst, int32_t shift, int line, int skip_line, int skip_line2)
{
  int j, k;
  int32_t a[5], b[5], c[5], d[5], t;
  int32_t add = (shift > 0) ? (1 << (shift - 1)) : 0;

  const int16_t *iT = uvg_g_DST7P16;

  const int  reduced_line = line - skip_line;

  for (j = 0; j < reduced_line; j++)
  {
    for (k = 0; k < 5; k++)
    {
      a[k] = src[k * line] + src[(10 - k) * line];
      b[k] = src[(11 + k) * line] + src[(10 - k) * line];
      c[k] = src[k * line] - src[(11 + k) * line];
      d[k] = src[k * line] + src[(11 + k) * line] - src[(10 - k)*line];
    }

    t = iT[10] * src[5 * line];

    dst[2] = (short)CLIP(-32768, 32767, (iT[2] * d[0] + iT[8] * d[1] + iT[14] * d[2] + iT[11] * d[3] + iT[5] * d[4] + add) >> shift);
    dst[5] = (short)CLIP(-32768, 32767, (iT[5] * d[0] + iT[14] * d[1] + iT[2] * d[2] - iT[8] * d[3] - iT[11] * d[4] + add) >> shift);
    dst[8] = (short)CLIP(-32768, 32767, (iT[8] * d[0] + iT[5] * d[1] - iT[11] * d[2] - iT[2] * d[3] + iT[14] * d[4] + add) >> shift);
    dst[11] = (short)CLIP(-32768, 32767, (iT[11] * d[0] - iT[2] * d[1] - iT[5] * d[2] + iT[14] * d[3] - iT[8] * d[4] + add) >> shift);
    dst[14] = (short)CLIP(-32768, 32767, (iT[14] * d[0] - iT[11] * d[1] + iT[8] * d[2] - iT[5] * d[3] + iT[2] * d[4] + add) >> shift);

    dst[10] = (short)CLIP(-32768, 32767, (iT[10] * (src[0 * line] - src[2 * line] + src[3 * line] - src[5 * line]
      + src[6 * line] - src[8 * line] + src[9 * line] - src[11 * line]
      + src[12 * line] - src[14 * line] + src[15 * line]) + add) >> shift);

    dst[0] = (short)CLIP(-32768, 32767, (iT[0] * a[0] + iT[9] * b[0] + iT[2] * a[1] + iT[7] * b[1] + iT[4] * a[2] + iT[5] * b[2] + iT[6] * a[3] + iT[3] * b[3] + iT[8] * a[4] + iT[1] * b[4] + t + add) >> shift);
    dst[1] = (short)CLIP(-32768, 32767, (iT[1] * c[0] - iT[8] * b[0] + iT[5] * c[1] - iT[4] * b[1] + iT[9] * c[2] - iT[0] * b[2] + iT[2] * a[3] + iT[7] * c[3] + iT[6] * a[4] + iT[3] * c[4] + t + add) >> shift);
    dst[3] = (short)CLIP(-32768, 32767, (iT[3] * a[0] + iT[6] * b[0] + iT[0] * c[1] + iT[9] * a[1] + iT[1] * a[2] + iT[8] * c[2] + iT[4] * c[3] - iT[5] * b[3] - iT[2] * a[4] - iT[7] * b[4] - t + add) >> shift);
    dst[4] = (short)CLIP(-32768, 32767, (iT[4] * c[0] - iT[5] * b[0] + iT[6] * c[1] + iT[3] * a[1] + iT[7] * a[2] + iT[2] * b[2] - iT[1] * c[3] + iT[8] * b[3] - iT[9] * c[4] - iT[0] * a[4] - t + add) >> shift);
    dst[6] = (short)CLIP(-32768, 32767, (iT[6] * a[0] + iT[3] * b[0] + iT[9] * c[1] + iT[0] * a[1] - iT[1] * a[2] - iT[8] * b[2] - iT[4] * c[3] - iT[5] * a[3] - iT[2] * c[4] + iT[7] * b[4] + t + add) >> shift);
    dst[7] = (short)CLIP(-32768, 32767, (iT[7] * c[0] - iT[2] * b[0] + iT[8] * a[1] + iT[1] * b[1] - iT[6] * c[2] + iT[3] * b[2] - iT[9] * a[3] - iT[0] * b[3] + iT[5] * c[4] - iT[4] * b[4] + t + add) >> shift);
    dst[9] = (short)CLIP(-32768, 32767, (iT[9] * a[0] + iT[0] * b[0] + iT[2] * c[1] - iT[7] * b[1] - iT[5] * c[2] - iT[4] * a[2] + iT[3] * a[3] + iT[6] * b[3] + iT[8] * c[4] - iT[1] * b[4] - t + add) >> shift);
    dst[12] = (short)CLIP(-32768, 32767, (iT[1] * c[0] + iT[8] * a[0] - iT[5] * a[1] - iT[4] * b[1] - iT[0] * c[2] + iT[9] * b[2] + iT[7] * c[3] - iT[2] * b[3] - iT[6] * c[4] - iT[3] * a[4] + t + add) >> shift);
    dst[13] = (short)CLIP(-32768, 32767, (iT[7] * c[0] + iT[2] * a[0] - iT[8] * c[1] + iT[1] * b[1] + iT[3] * c[2] - iT[6] * b[2] + iT[0] * a[3] + iT[9] * b[3] - iT[5] * a[4] - iT[4] * b[4] + t + add) >> shift);
    dst[15] = (short)CLIP(-32768, 32767, (iT[4] * c[0] + iT[5] * a[0] - iT[3] * c[1] - iT[6] * a[1] + iT[2] * c[2] + iT[7] * a[2] - iT[1] * c[3] - iT[8] * a[3] + iT[0] * c[4] + iT[9] * a[4] - t + add) >> shift);
    src++;
    dst += 16;
  }

  if (skip_line)
  {
    memset(dst, 0, (skip_line * 16) * sizeof(int16_t));
  }
}

static void fastForwardDST7_B32(const int16_t *src, int16_t *dst, int32_t shift, int line, int skip_line, int skip_line2)
{
  int j, k;
  int32_t a[10][6];
  int32_t t[2];
  int32_t b[6];
  int32_t c[2];

  int32_t add = (shift > 0) ? (1 << (shift - 1)) : 0;
  const int16_t *iT = uvg_g_DST7P32;
  int16_t *p_coef = dst;
  const int  reduced_line = line - skip_line;
  const int  cutoff = 32 - skip_line2;

  for (j = 0; j < reduced_line; j++)
  {
    for (k = 0; k < 6; k++)
    {
      a[0][k] = src[k] - src[11 - k];
      a[1][k] = src[k] + src[13 + k];
      a[2][k] = src[k] + src[24 - k];
      a[3][k] = src[k] - src[26 + k];
      a[4][k] = src[6 + k] + src[18 - k];
      a[5][k] = src[6 + k] + src[19 + k];
      a[6][k] = src[6 + k] - src[31 - k];
      a[7][k] = src[13 + k] - src[24 - k];
      a[8][k] = src[13 + k] + src[26 + k];
      a[9][k] = src[19 + k] + src[31 - k];

      b[k] = src[k] + src[11 - k] - src[13 + k] - src[24 - k] + src[26 + k];
    }
    for (k = 0; k < 2; k++)
    {
      c[k] = src[k] + src[3 - k] - src[5 + k] - src[8 - k] + src[10 + k] + src[13 - k] - src[15 + k] - src[18 - k] + src[20 + k] + src[23 - k] - src[25 + k] - src[28 - k] + src[30 + k];
    }

    t[0] = iT[12] * src[12] + iT[25] * src[25];
    t[1] = iT[12] * src[25] - iT[25] * src[12];

    dst[0 * line] = (iT[0] * a[3][0] + iT[11] * a[6][5] + iT[13] * a[8][0] + iT[24] * a[9][5] + iT[1] * a[3][1] + iT[10] * a[6][4] + iT[14] * a[8][1] + iT[23] * a[9][4] + iT[2] * a[3][2] + iT[9] * a[6][3] + iT[15] * a[8][2] + iT[22] * a[9][3] + iT[3] * a[3][3] + iT[8] * a[6][2] + iT[16] * a[8][3] + iT[21] * a[9][2] + iT[4] * a[3][4] + iT[7] * a[6][1] + iT[17] * a[8][4] + iT[20] * a[9][1] + iT[5] * a[3][5] + iT[6] * a[6][0] + iT[18] * a[8][5] + iT[19] * a[9][0] + t[0] + add) >> shift;
    dst[1 * line] = (-iT[0] * a[5][2] + iT[11] * a[0][3] + iT[13] * a[4][2] + iT[24] * a[6][2] + iT[1] * a[9][1] + iT[10] * a[8][4] + iT[14] * a[3][4] + iT[23] * a[6][1] + iT[2] * a[0][0] - iT[9] * a[5][5] + iT[15] * a[6][5] + iT[22] * a[4][5] - iT[3] * a[5][3] + iT[8] * a[0][2] + iT[16] * a[4][3] + iT[21] * a[6][3] + iT[4] * a[9][0] + iT[7] * a[8][5] + iT[17] * a[3][5] + iT[20] * a[6][0] + iT[5] * a[0][1] - iT[6] * a[5][4] + iT[18] * a[6][4] + iT[19] * a[4][4] - t[1] + add) >> shift;
    dst[3 * line] = (-iT[0] * a[9][4] - iT[11] * a[5][4] + iT[13] * a[2][1] - iT[24] * a[7][1] - iT[1] * a[0][3] - iT[10] * a[1][3] + iT[14] * a[3][3] + iT[23] * a[2][3] + iT[2] * a[8][5] + iT[9] * a[9][0] + iT[15] * a[6][0] + iT[22] * a[3][5] - iT[3] * a[1][4] - iT[8] * a[0][4] + iT[16] * a[2][4] + iT[21] * a[3][4] - iT[4] * a[5][3] - iT[7] * a[9][3] - iT[17] * a[7][2] + iT[20] * a[2][2] + iT[5] * a[8][0] + iT[6] * a[1][0] - iT[18] * a[4][5] - iT[19] * a[7][0] + t[1] + add) >> shift;
    dst[4 * line] = (-iT[0] * a[3][2] - iT[11] * a[2][2] + iT[13] * a[1][2] + iT[24] * a[0][2] + iT[1] * a[6][0] + iT[10] * a[3][5] + iT[14] * a[9][0] + iT[23] * a[8][5] - iT[2] * a[2][3] - iT[9] * a[3][3] + iT[15] * a[0][3] + iT[22] * a[1][3] - iT[3] * a[7][0] + iT[8] * a[2][0] - iT[16] * a[9][5] - iT[21] * a[5][5] + iT[4] * a[4][4] + iT[7] * a[6][4] + iT[17] * a[0][1] - iT[20] * a[5][4] - iT[5] * a[7][4] - iT[6] * a[4][1] + iT[18] * a[8][4] + iT[19] * a[1][4] - t[0] + add) >> shift;
    dst[5 * line] = (-iT[0] * a[3][5] - iT[11] * a[6][0] - iT[13] * a[8][5] - iT[24] * a[9][0] + iT[1] * a[6][5] + iT[10] * a[3][0] + iT[14] * a[9][5] + iT[23] * a[8][0] - iT[2] * a[7][4] + iT[9] * a[2][4] - iT[15] * a[9][1] - iT[22] * a[5][1] - iT[3] * a[7][1] - iT[8] * a[4][4] + iT[16] * a[8][1] + iT[21] * a[1][1] + iT[4] * a[6][2] + iT[7] * a[4][2] - iT[17] * a[5][2] + iT[20] * a[0][3] - iT[5] * a[3][2] - iT[6] * a[2][2] + iT[18] * a[1][2] + iT[19] * a[0][2] + t[0] + add) >> shift;
    dst[8 * line] = (iT[0] * a[9][3] + iT[11] * a[8][2] + iT[13] * a[3][2] + iT[24] * a[6][3] + iT[1] * a[1][5] + iT[10] * a[0][5] - iT[14] * a[2][5] - iT[23] * a[3][5] - iT[2] * a[1][3] - iT[9] * a[8][3] + iT[15] * a[7][3] + iT[22] * a[4][2] - iT[3] * a[9][5] - iT[8] * a[5][5] + iT[16] * a[2][0] - iT[21] * a[7][0] - iT[4] * a[1][1] - iT[7] * a[0][1] + iT[17] * a[2][1] + iT[20] * a[3][1] + iT[5] * a[5][1] + iT[6] * a[9][1] + iT[18] * a[7][4] - iT[19] * a[2][4] + t[1] + add) >> shift;
    dst[9 * line] = (-iT[0] * a[2][1] - iT[11] * a[3][1] + iT[13] * a[0][1] + iT[24] * a[1][1] + iT[1] * a[7][3] - iT[10] * a[2][3] + iT[14] * a[9][2] + iT[23] * a[5][2] + iT[2] * a[4][0] + iT[9] * a[7][5] - iT[15] * a[1][5] - iT[22] * a[8][5] + iT[3] * a[3][4] + iT[8] * a[2][4] - iT[16] * a[1][4] - iT[21] * a[0][4] + iT[4] * a[6][3] + iT[7] * a[3][2] + iT[17] * a[9][3] + iT[20] * a[8][2] + iT[5] * a[4][5] + iT[6] * a[6][5] + iT[18] * a[0][0] - iT[19] * a[5][5] - t[0] + add) >> shift;
    dst[10 * line] = (-iT[0] * a[6][1] - iT[11] * a[4][1] + iT[13] * a[5][1] - iT[24] * a[0][4] + iT[1] * a[2][2] - iT[10] * a[7][2] - iT[14] * a[5][3] - iT[23] * a[9][3] + iT[2] * a[6][4] + iT[9] * a[4][4] - iT[15] * a[5][4] + iT[22] * a[0][1] - iT[3] * a[2][5] + iT[8] * a[7][5] + iT[16] * a[5][0] + iT[21] * a[9][0] - iT[4] * a[7][0] - iT[7] * a[4][5] + iT[17] * a[8][0] + iT[20] * a[1][0] + iT[5] * a[4][2] + iT[6] * a[7][3] - iT[18] * a[1][3] - iT[19] * a[8][3] + t[0] + add) >> shift;
    dst[11 * line] = (iT[0] * a[1][3] + iT[11] * a[0][3] - iT[13] * a[2][3] - iT[24] * a[3][3] + iT[1] * a[9][1] + iT[10] * a[5][1] - iT[14] * a[2][4] + iT[23] * a[7][4] + iT[2] * a[8][0] + iT[9] * a[9][5] + iT[15] * a[6][5] + iT[22] * a[3][0] - iT[3] * a[0][2] + iT[8] * a[5][3] - iT[16] * a[6][3] - iT[21] * a[4][3] - iT[4] * a[5][0] + iT[7] * a[0][5] + iT[17] * a[4][0] + iT[20] * a[6][0] - iT[5] * a[9][4] - iT[6] * a[5][4] + iT[18] * a[2][1] - iT[19] * a[7][1] - t[1] + add) >> shift;
    dst[13 * line] = (-iT[0] * a[0][0] - iT[11] * a[1][0] + iT[13] * a[3][0] + iT[24] * a[2][0] - iT[1] * a[5][4] + iT[10] * a[0][1] + iT[14] * a[4][4] + iT[23] * a[6][4] + iT[2] * a[9][3] + iT[9] * a[5][3] - iT[15] * a[2][2] + iT[22] * a[7][2] - iT[3] * a[8][3] - iT[8] * a[9][2] - iT[16] * a[6][2] - iT[21] * a[3][3] + iT[4] * a[1][4] + iT[7] * a[8][4] - iT[17] * a[7][4] - iT[20] * a[4][1] - iT[5] * a[0][5] - iT[6] * a[1][5] + iT[18] * a[3][5] + iT[19] * a[2][5] + t[1] + add) >> shift;
    dst[14 * line] = (iT[0] * a[4][2] + iT[11] * a[7][3] - iT[13] * a[1][3] - iT[24] * a[8][3] + iT[1] * a[4][1] + iT[10] * a[6][1] + iT[14] * a[0][4] - iT[23] * a[5][1] - iT[2] * a[3][0] - iT[9] * a[2][0] + iT[15] * a[1][0] + iT[22] * a[0][0] - iT[3] * a[6][3] - iT[8] * a[4][3] + iT[16] * a[5][3] - iT[21] * a[0][2] - iT[4] * a[7][5] - iT[7] * a[4][0] + iT[17] * a[8][5] + iT[20] * a[1][5] + iT[5] * a[6][4] + iT[6] * a[3][1] + iT[18] * a[9][4] + iT[19] * a[8][1] - t[0] + add) >> shift;
    dst[15 * line] = (-iT[0] * a[7][4] - iT[11] * a[4][1] + iT[13] * a[8][4] + iT[24] * a[1][4] + iT[1] * a[2][2] + iT[10] * a[3][2] - iT[14] * a[0][2] - iT[23] * a[1][2] + iT[2] * a[2][1] - iT[9] * a[7][1] - iT[15] * a[5][4] - iT[22] * a[9][4] - iT[3] * a[7][5] + iT[8] * a[2][5] - iT[16] * a[9][0] - iT[21] * a[5][0] - iT[4] * a[2][0] - iT[7] * a[3][0] + iT[17] * a[0][0] + iT[20] * a[1][0] - iT[5] * a[2][3] + iT[6] * a[7][3] + iT[18] * a[5][2] + iT[19] * a[9][2] + t[0] + add) >> shift;
    dst[16 * line] = (-iT[0] * a[0][1] + iT[11] * a[5][4] - iT[13] * a[6][4] - iT[24] * a[4][4] + iT[1] * a[0][3] - iT[10] * a[5][2] + iT[14] * a[6][2] + iT[23] * a[4][2] - iT[2] * a[0][5] + iT[9] * a[5][0] - iT[15] * a[6][0] - iT[22] * a[4][0] - iT[3] * a[0][4] - iT[8] * a[1][4] + iT[16] * a[3][4] + iT[21] * a[2][4] + iT[4] * a[0][2] + iT[7] * a[1][2] - iT[17] * a[3][2] - iT[20] * a[2][2] - iT[5] * a[0][0] - iT[6] * a[1][0] + iT[18] * a[3][0] + iT[19] * a[2][0] - t[1] + add) >> shift;
    dst[18 * line] = (iT[0] * a[0][5] + iT[11] * a[1][5] - iT[13] * a[3][5] - iT[24] * a[2][5] - iT[1] * a[1][0] - iT[10] * a[0][0] + iT[14] * a[2][0] + iT[23] * a[3][0] - iT[2] * a[5][1] + iT[9] * a[0][4] + iT[15] * a[4][1] + iT[22] * a[6][1] - iT[3] * a[8][1] - iT[8] * a[1][1] + iT[16] * a[4][4] + iT[21] * a[7][1] - iT[4] * a[9][2] - iT[7] * a[5][2] + iT[17] * a[2][3] - iT[20] * a[7][3] - iT[5] * a[9][3] - iT[6] * a[8][2] - iT[18] * a[3][2] - iT[19] * a[6][3] + t[1] + add) >> shift;
    dst[20 * line] = (-iT[0] * a[4][0] - iT[11] * a[6][0] - iT[13] * a[0][5] + iT[24] * a[5][0] + iT[1] * a[6][5] + iT[10] * a[4][5] - iT[14] * a[5][5] + iT[23] * a[0][0] - iT[2] * a[6][1] - iT[9] * a[3][4] - iT[15] * a[9][1] - iT[22] * a[8][4] + iT[3] * a[4][4] + iT[8] * a[7][1] - iT[16] * a[1][1] - iT[21] * a[8][1] - iT[4] * a[3][3] - iT[7] * a[2][3] + iT[17] * a[1][3] + iT[20] * a[0][3] + iT[5] * a[7][2] - iT[6] * a[2][2] + iT[18] * a[9][3] + iT[19] * a[5][3] + t[0] + add) >> shift;
    dst[21 * line] = (-iT[0] * a[1][2] - iT[11] * a[8][2] + iT[13] * a[7][2] + iT[24] * a[4][3] - iT[1] * a[1][5] - iT[10] * a[8][5] + iT[14] * a[7][5] + iT[23] * a[4][0] - iT[2] * a[5][2] - iT[9] * a[9][2] - iT[15] * a[7][3] + iT[22] * a[2][3] - iT[3] * a[5][5] - iT[8] * a[9][5] - iT[16] * a[7][0] + iT[21] * a[2][0] - iT[4] * a[8][1] - iT[7] * a[9][4] - iT[17] * a[6][4] - iT[20] * a[3][1] - iT[5] * a[8][4] - iT[6] * a[9][1] - iT[18] * a[6][1] - iT[19] * a[3][4] - t[1] + add) >> shift;
    dst[23 * line] = (-iT[0] * a[8][4] - iT[11] * a[9][1] - iT[13] * a[6][1] - iT[24] * a[3][4] + iT[1] * a[8][2] + iT[10] * a[1][2] - iT[14] * a[4][3] - iT[23] * a[7][2] + iT[2] * a[0][1] + iT[9] * a[1][1] - iT[15] * a[3][1] - iT[22] * a[2][1] - iT[3] * a[5][0] - iT[8] * a[9][0] - iT[16] * a[7][5] + iT[21] * a[2][5] + iT[4] * a[9][5] + iT[7] * a[8][0] + iT[17] * a[3][0] + iT[20] * a[6][5] - iT[5] * a[5][2] + iT[6] * a[0][3] + iT[18] * a[4][2] + iT[19] * a[6][2] + t[1] + add) >> shift;
    dst[24 * line] = (-iT[0] * a[2][3] + iT[11] * a[7][3] + iT[13] * a[5][2] + iT[24] * a[9][2] + iT[1] * a[4][1] + iT[10] * a[7][4] - iT[14] * a[1][4] - iT[23] * a[8][4] - iT[2] * a[4][5] - iT[9] * a[7][0] + iT[15] * a[1][0] + iT[22] * a[8][0] + iT[3] * a[4][3] + iT[8] * a[6][3] + iT[16] * a[0][2] - iT[21] * a[5][3] - iT[4] * a[2][5] - iT[7] * a[3][5] + iT[17] * a[0][5] + iT[20] * a[1][5] + iT[5] * a[2][1] + iT[6] * a[3][1] - iT[18] * a[0][1] - iT[19] * a[1][1] - t[0] + add) >> shift;
    dst[25 * line] = (iT[0] * a[4][5] + iT[11] * a[6][5] + iT[13] * a[0][0] - iT[24] * a[5][5] + iT[1] * a[3][1] + iT[10] * a[2][1] - iT[14] * a[1][1] - iT[23] * a[0][1] - iT[2] * a[7][2] - iT[9] * a[4][3] + iT[15] * a[8][2] + iT[22] * a[1][2] - iT[3] * a[6][2] - iT[8] * a[3][3] - iT[16] * a[9][2] - iT[21] * a[8][3] - iT[4] * a[2][4] + iT[7] * a[7][4] + iT[17] * a[5][1] + iT[20] * a[9][1] + iT[5] * a[4][0] + iT[6] * a[6][0] + iT[18] * a[0][5] - iT[19] * a[5][0] + t[0] + add) >> shift;
    dst[26 * line] = (iT[0] * a[8][0] + iT[11] * a[1][0] - iT[13] * a[4][5] - iT[24] * a[7][0] + iT[1] * a[5][4] + iT[10] * a[9][4] + iT[14] * a[7][1] - iT[23] * a[2][1] - iT[2] * a[1][2] - iT[9] * a[0][2] + iT[15] * a[2][2] + iT[22] * a[3][2] - iT[3] * a[9][2] - iT[8] * a[8][3] - iT[16] * a[3][3] - iT[21] * a[6][2] + iT[4] * a[0][4] - iT[7] * a[5][1] + iT[17] * a[6][1] + iT[20] * a[4][1] + iT[5] * a[8][5] + iT[6] * a[1][5] - iT[18] * a[4][0] - iT[19] * a[7][5] - t[1] + add) >> shift;
    dst[28 * line] = (-iT[0] * a[5][1] - iT[11] * a[9][1] - iT[13] * a[7][4] + iT[24] * a[2][4] + iT[1] * a[8][2] + iT[10] * a[9][3] + iT[14] * a[6][3] + iT[23] * a[3][2] - iT[2] * a[9][4] - iT[9] * a[8][1] - iT[15] * a[3][1] - iT[22] * a[6][4] + iT[3] * a[9][0] + iT[8] * a[5][0] - iT[16] * a[2][5] + iT[21] * a[7][5] - iT[4] * a[5][5] + iT[7] * a[0][0] + iT[17] * a[4][5] + iT[20] * a[6][5] + iT[5] * a[1][3] + iT[6] * a[0][3] - iT[18] * a[2][3] - iT[19] * a[3][3] + t[1] + add) >> shift;
    dst[29 * line] = (-iT[0] * a[6][4] - iT[11] * a[3][1] - iT[13] * a[9][4] - iT[24] * a[8][1] + iT[1] * a[7][3] + iT[10] * a[4][2] - iT[14] * a[8][3] - iT[23] * a[1][3] + iT[2] * a[3][5] + iT[9] * a[2][5] - iT[15] * a[1][5] - iT[22] * a[0][5] - iT[3] * a[2][4] - iT[8] * a[3][4] + iT[16] * a[0][4] + iT[21] * a[1][4] - iT[4] * a[4][3] - iT[7] * a[7][2] + iT[17] * a[1][2] + iT[20] * a[8][2] + iT[5] * a[3][0] + iT[6] * a[6][5] + iT[18] * a[8][0] + iT[19] * a[9][5] - t[0] + add) >> shift;
    dst[30 * line] = (-iT[0] * a[7][2] + iT[11] * a[2][2] - iT[13] * a[9][3] - iT[24] * a[5][3] - iT[1] * a[6][0] - iT[10] * a[4][0] + iT[14] * a[5][0] - iT[23] * a[0][5] - iT[2] * a[4][2] - iT[9] * a[6][2] - iT[15] * a[0][3] + iT[22] * a[5][2] + iT[3] * a[2][0] - iT[8] * a[7][0] - iT[16] * a[5][5] - iT[21] * a[9][5] + iT[4] * a[7][1] - iT[7] * a[2][1] + iT[17] * a[9][4] + iT[20] * a[5][4] + iT[5] * a[6][1] + iT[6] * a[4][1] - iT[18] * a[5][1] + iT[19] * a[0][4] + t[0] + add) >> shift;
    dst[31 * line] = (-iT[0] * a[8][5] - iT[11] * a[1][5] + iT[13] * a[4][0] + iT[24] * a[7][5] + iT[1] * a[1][0] + iT[10] * a[8][0] - iT[14] * a[7][0] - iT[23] * a[4][5] + iT[2] * a[8][4] + iT[9] * a[1][4] - iT[15] * a[4][1] - iT[22] * a[7][4] - iT[3] * a[1][1] - iT[8] * a[8][1] + iT[16] * a[7][1] + iT[21] * a[4][4] - iT[4] * a[8][3] - iT[7] * a[1][3] + iT[17] * a[4][2] + iT[20] * a[7][3] + iT[5] * a[1][2] + iT[6] * a[8][2] - iT[18] * a[7][2] - iT[19] * a[4][3] - t[1] + add) >> shift;

    dst[2 * line] = (iT[4] * b[0] + iT[9] * b[1] + iT[14] * b[2] + iT[19] * b[3] + iT[24] * b[4] + iT[29] * b[5] + add) >> shift;
    dst[7 * line] = (iT[14] * b[0] + iT[29] * b[1] + iT[19] * b[2] + iT[4] * b[3] - iT[9] * b[4] - iT[24] * b[5] + add) >> shift;
    dst[12 * line] = (iT[24] * b[0] + iT[14] * b[1] - iT[9] * b[2] - iT[29] * b[3] - iT[4] * b[4] + iT[19] * b[5] + add) >> shift;
    dst[17 * line] = (iT[29] * b[0] - iT[4] * b[1] - iT[24] * b[2] + iT[9] * b[3] + iT[19] * b[4] - iT[14] * b[5] + add) >> shift;
    dst[22 * line] = (iT[19] * b[0] - iT[24] * b[1] + iT[4] * b[2] + iT[14] * b[3] - iT[29] * b[4] + iT[9] * b[5] + add) >> shift;
    dst[27 * line] = (iT[9] * b[0] - iT[19] * b[1] + iT[29] * b[2] - iT[24] * b[3] + iT[14] * b[4] - iT[4] * b[5] + add) >> shift;

    dst[6 * line] = (iT[12] * c[0] + iT[25] * c[1] + add) >> shift;
    dst[19 * line] = (iT[25] * c[0] - iT[12] * c[1] + add) >> shift;

    src += 32;
    dst++;
  }

  if (skip_line)
  {
    dst = p_coef + reduced_line;
    for (j = 0; j < cutoff; j++)
    {
      memset(dst, 0, sizeof(int16_t)*skip_line);
      dst += line;
    }
  }

  if (skip_line2)
  {
    dst = p_coef + line * cutoff;
    memset(dst, 0, sizeof(int16_t) * line * skip_line2);
  }
}

static void fastInverseDST7_B32(const int16_t *src, int16_t *dst, int32_t shift, int line, int skip_line, int skip_line2)
{
  int j, k;
  int32_t a[10][6];
  int32_t t[2];
  int32_t b[6];
  int32_t c[2];

  int32_t add = (shift > 0) ? (1 << (shift - 1)) : 0;
  const int16_t *iT = uvg_g_DST7P32;
  const int  reduced_line = line - skip_line;

  for (j = 0; j < reduced_line; j++)
  {
    for (k = 0; k < 6; k++)
    {
      a[0][k] = src[k  * line] + src[(12 - k) * line];
      a[1][k] = src[k  * line] - src[(13 + k) * line];
      a[2][k] = src[k  * line] + src[(25 - k) * line];
      a[3][k] = src[k  * line] - src[(26 + k) * line];
      a[4][k] = src[(7 + k) * line] + src[(18 - k) * line];
      a[5][k] = src[(7 + k) * line] - src[(20 + k) * line];
      a[6][k] = src[(7 + k) * line] + src[(31 - k) * line];
      a[7][k] = src[(13 + k) * line] + src[(25 - k) * line];
      a[8][k] = src[(13 + k) * line] - src[(26 + k) * line];
      a[9][k] = src[(20 + k) * line] + src[(31 - k) * line];

      b[k] = src[k * line] - src[(12 - k) * line] + src[(13 + k) * line] - src[(25 - k) * line] + src[(26 + k) * line];
    }
    for (k = 0; k < 2; k++)
    {
      c[k] = src[k * line] - src[(4 - k) * line] + src[(5 + k) * line] - src[(9 - k) * line] + src[(10 + k) * line] - src[(14 - k) * line] + src[(15 + k)*line] - src[(19 - k)*line] + src[(20 + k)*line] - src[(24 - k)*line] + src[(25 + k)*line] - src[(29 - k)*line] + src[(30 + k)*line];
    }

    t[0] = iT[12] * src[6 * line] + iT[25] * src[19 * line];
    t[1] = iT[25] * src[6 * line] - iT[12] * src[19 * line];

    dst[0] = (short)CLIP(-32768, 32767, (iT[0] * a[1][0] - iT[11] * a[8][0] + iT[13] * a[7][0] + iT[24] * a[4][5] - iT[1] * a[8][5] + iT[10] * a[1][5] + iT[14] * a[4][0] + iT[23] * a[7][5] + iT[2] * a[1][1] - iT[9] * a[8][1] + iT[15] * a[7][1] + iT[22] * a[4][4] - iT[3] * a[8][4] + iT[8] * a[1][4] + iT[16] * a[4][1] + iT[21] * a[7][4] + iT[4] * a[1][2] - iT[7] * a[8][2] + iT[17] * a[7][2] + iT[20] * a[4][3] - iT[5] * a[8][3] + iT[6] * a[1][3] + iT[18] * a[4][2] + iT[19] * a[7][3] + t[0] + add) >> shift);
    dst[1] = (short)CLIP(-32768, 32767, (-iT[0] * a[4][2] - iT[11] * a[6][2] + iT[13] * a[0][3] + iT[24] * a[5][2] + iT[1] * a[2][0] + iT[10] * a[7][0] + iT[14] * a[5][5] - iT[23] * a[9][5] + iT[2] * a[7][2] + iT[9] * a[2][2] - iT[15] * a[9][3] + iT[22] * a[5][3] - iT[3] * a[6][0] - iT[8] * a[4][0] + iT[16] * a[5][0] + iT[21] * a[0][5] - iT[4] * a[4][1] - iT[7] * a[6][1] + iT[17] * a[0][4] + iT[20] * a[5][1] + iT[5] * a[2][1] + iT[6] * a[7][1] + iT[18] * a[5][4] - iT[19] * a[9][4] + t[1] + add) >> shift);
    dst[2] = (short)CLIP(-32768, 32767, (-iT[0] * a[2][4] - iT[11] * a[3][4] + iT[13] * a[0][4] + iT[24] * a[1][4] + iT[1] * a[4][3] + iT[10] * a[7][2] + iT[14] * a[1][2] - iT[23] * a[8][2] + iT[2] * a[3][0] - iT[9] * a[6][5] - iT[15] * a[8][0] + iT[22] * a[9][5] - iT[3] * a[6][4] + iT[8] * a[3][1] + iT[16] * a[9][4] - iT[21] * a[8][1] + iT[4] * a[7][3] + iT[7] * a[4][2] - iT[17] * a[8][3] + iT[20] * a[1][3] - iT[5] * a[3][5] - iT[6] * a[2][5] + iT[18] * a[1][5] + iT[19] * a[0][5] + t[1] + add) >> shift);
    dst[3] = (short)CLIP(-32768, 32767, (iT[0] * a[5][4] + iT[11] * a[0][1] - iT[13] * a[4][4] - iT[24] * a[6][4] - iT[1] * a[1][3] - iT[10] * a[0][3] + iT[14] * a[2][3] + iT[23] * a[3][3] - iT[2] * a[0][4] - iT[9] * a[1][4] + iT[15] * a[3][4] + iT[22] * a[2][4] + iT[3] * a[0][0] + iT[8] * a[5][5] - iT[16] * a[6][5] - iT[21] * a[4][5] + iT[4] * a[5][0] - iT[7] * a[9][0] + iT[17] * a[7][5] + iT[20] * a[2][5] - iT[5] * a[8][2] + iT[6] * a[9][3] - iT[18] * a[6][3] + iT[19] * a[3][2] + t[0] + add) >> shift);
    dst[5] = (short)CLIP(-32768, 32767, (-iT[0] * a[1][5] + iT[11] * a[8][5] - iT[13] * a[7][5] - iT[24] * a[4][0] + iT[1] * a[5][1] + iT[10] * a[0][4] - iT[14] * a[4][1] - iT[23] * a[6][1] - iT[2] * a[8][3] + iT[9] * a[9][2] - iT[15] * a[6][2] + iT[22] * a[3][3] - iT[3] * a[0][2] - iT[8] * a[1][2] + iT[16] * a[3][2] + iT[21] * a[2][2] - iT[4] * a[9][4] + iT[7] * a[5][4] + iT[17] * a[2][1] + iT[20] * a[7][1] + iT[5] * a[1][0] - iT[6] * a[8][0] + iT[18] * a[7][0] + iT[19] * a[4][5] - t[0] + add) >> shift);
    dst[6] = (short)CLIP(-32768, 32767, (-iT[0] * a[7][5] - iT[11] * a[2][5] + iT[13] * a[9][0] - iT[24] * a[5][0] + iT[1] * a[3][4] - iT[10] * a[6][1] - iT[14] * a[8][4] + iT[23] * a[9][1] + iT[2] * a[4][2] + iT[9] * a[7][3] + iT[15] * a[1][3] - iT[22] * a[8][3] - iT[3] * a[2][2] - iT[8] * a[3][2] + iT[16] * a[0][2] + iT[21] * a[1][2] - iT[4] * a[6][4] - iT[7] * a[4][4] + iT[17] * a[5][4] + iT[20] * a[0][1] + iT[5] * a[7][0] + iT[6] * a[2][0] - iT[18] * a[9][5] + iT[19] * a[5][5] - t[1] + add) >> shift);
    dst[7] = (short)CLIP(-32768, 32767, (-iT[0] * a[6][3] - iT[11] * a[4][3] + iT[13] * a[5][3] + iT[24] * a[0][2] + iT[1] * a[7][1] + iT[10] * a[4][4] - iT[14] * a[8][1] + iT[23] * a[1][1] - iT[2] * a[7][5] - iT[9] * a[4][0] + iT[15] * a[8][5] - iT[22] * a[1][5] + iT[3] * a[7][3] + iT[8] * a[2][3] - iT[16] * a[9][2] + iT[21] * a[5][2] - iT[4] * a[6][5] + iT[7] * a[3][0] + iT[17] * a[9][5] - iT[20] * a[8][0] + iT[5] * a[6][1] - iT[6] * a[3][4] - iT[18] * a[9][1] + iT[19] * a[8][4] - t[1] + add) >> shift);
    dst[8] = (short)CLIP(-32768, 32767, (-iT[0] * a[1][1] - iT[11] * a[0][1] + iT[13] * a[2][1] + iT[24] * a[3][1] + iT[1] * a[1][3] - iT[10] * a[8][3] + iT[14] * a[7][3] + iT[23] * a[4][2] - iT[2] * a[9][1] + iT[9] * a[8][4] - iT[15] * a[3][4] + iT[22] * a[6][1] + iT[3] * a[5][5] + iT[8] * a[0][0] - iT[16] * a[4][5] - iT[21] * a[6][5] + iT[4] * a[0][5] + iT[7] * a[1][5] - iT[17] * a[3][5] - iT[20] * a[2][5] + iT[5] * a[5][3] - iT[6] * a[9][3] + iT[18] * a[7][2] + iT[19] * a[2][2] - t[0] + add) >> shift);
    dst[10] = (short)CLIP(-32768, 32767, (iT[0] * a[8][3] - iT[11] * a[1][3] - iT[13] * a[4][2] - iT[24] * a[7][3] - iT[1] * a[8][0] + iT[10] * a[1][0] + iT[14] * a[4][5] + iT[23] * a[7][0] + iT[2] * a[5][3] + iT[9] * a[0][2] - iT[15] * a[4][3] - iT[22] * a[6][3] - iT[3] * a[5][0] - iT[8] * a[0][5] + iT[16] * a[4][0] + iT[21] * a[6][0] + iT[4] * a[1][4] + iT[7] * a[0][4] - iT[17] * a[2][4] - iT[20] * a[3][4] - iT[5] * a[1][1] - iT[6] * a[0][1] + iT[18] * a[2][1] + iT[19] * a[3][1] + t[0] + add) >> shift);
    dst[11] = (short)CLIP(-32768, 32767, (iT[0] * a[7][0] + iT[11] * a[2][0] - iT[13] * a[9][5] + iT[24] * a[5][5] + iT[1] * a[2][5] + iT[10] * a[7][5] + iT[14] * a[5][0] - iT[23] * a[9][0] - iT[2] * a[2][1] - iT[9] * a[3][1] + iT[15] * a[0][1] + iT[22] * a[1][1] - iT[3] * a[7][4] - iT[8] * a[4][1] + iT[16] * a[8][4] - iT[21] * a[1][4] + iT[4] * a[3][2] - iT[7] * a[6][3] - iT[17] * a[8][2] + iT[20] * a[9][3] + iT[5] * a[4][2] + iT[6] * a[6][2] - iT[18] * a[0][3] - iT[19] * a[5][2] + t[1] + add) >> shift);
    dst[13] = (short)CLIP(-32768, 32767, (iT[0] * a[9][5] - iT[11] * a[8][0] + iT[13] * a[3][0] - iT[24] * a[6][5] - iT[1] * a[8][5] + iT[10] * a[9][0] - iT[14] * a[6][0] + iT[23] * a[3][5] + iT[2] * a[5][4] - iT[9] * a[9][4] + iT[15] * a[7][1] + iT[22] * a[2][1] - iT[3] * a[1][4] + iT[8] * a[8][4] - iT[16] * a[7][4] - iT[21] * a[4][1] - iT[4] * a[0][2] - iT[7] * a[5][3] + iT[17] * a[6][3] + iT[20] * a[4][3] + iT[5] * a[0][3] + iT[6] * a[1][3] - iT[18] * a[3][3] - iT[19] * a[2][3] + t[0] + add) >> shift);
    dst[15] = (short)CLIP(-32768, 32767, (-iT[0] * a[9][1] + iT[11] * a[5][1] + iT[13] * a[2][4] + iT[24] * a[7][4] + iT[1] * a[9][3] - iT[10] * a[5][3] - iT[14] * a[2][2] - iT[23] * a[7][2] - iT[2] * a[9][5] + iT[9] * a[5][5] + iT[15] * a[2][0] + iT[22] * a[7][0] + iT[3] * a[9][4] - iT[8] * a[8][1] + iT[16] * a[3][1] - iT[21] * a[6][4] - iT[4] * a[9][2] + iT[7] * a[8][3] - iT[17] * a[3][3] + iT[20] * a[6][2] + iT[5] * a[9][0] - iT[6] * a[8][5] + iT[18] * a[3][5] - iT[19] * a[6][0] - t[0] + add) >> shift);
    dst[16] = (short)CLIP(-32768, 32767, (iT[0] * a[4][4] + iT[11] * a[7][1] + iT[13] * a[1][1] - iT[24] * a[8][1] + iT[1] * a[6][2] - iT[10] * a[3][3] - iT[14] * a[9][2] + iT[23] * a[8][3] - iT[2] * a[6][1] - iT[9] * a[4][1] + iT[15] * a[5][1] + iT[22] * a[0][4] - iT[3] * a[4][5] - iT[8] * a[6][5] + iT[16] * a[0][0] + iT[21] * a[5][5] - iT[4] * a[6][0] + iT[7] * a[3][5] + iT[17] * a[9][0] - iT[20] * a[8][5] + iT[5] * a[6][3] + iT[6] * a[4][3] - iT[18] * a[5][3] - iT[19] * a[0][2] - t[1] + add) >> shift);
    dst[17] = (short)CLIP(-32768, 32767, (-iT[0] * a[7][2] - iT[11] * a[4][3] + iT[13] * a[8][2] - iT[24] * a[1][2] + iT[1] * a[7][1] + iT[10] * a[2][1] - iT[14] * a[9][4] + iT[23] * a[5][4] - iT[2] * a[3][5] + iT[9] * a[6][0] + iT[15] * a[8][5] - iT[22] * a[9][0] - iT[3] * a[2][3] - iT[8] * a[7][3] - iT[16] * a[5][2] + iT[21] * a[9][2] + iT[4] * a[4][5] + iT[7] * a[7][0] + iT[17] * a[1][0] - iT[20] * a[8][0] - iT[5] * a[2][4] - iT[6] * a[3][4] + iT[18] * a[0][4] + iT[19] * a[1][4] - t[1] + add) >> shift);
    dst[18] = (short)CLIP(-32768, 32767, (-iT[0] * a[9][0] + iT[11] * a[8][5] - iT[13] * a[3][5] + iT[24] * a[6][0] + iT[1] * a[5][1] - iT[10] * a[9][1] + iT[14] * a[7][4] + iT[23] * a[2][4] + iT[2] * a[0][3] + iT[9] * a[5][2] - iT[15] * a[6][2] - iT[22] * a[4][2] + iT[3] * a[1][2] + iT[8] * a[0][2] - iT[16] * a[2][2] - iT[21] * a[3][2] - iT[4] * a[8][1] + iT[7] * a[1][1] + iT[17] * a[4][4] + iT[20] * a[7][1] + iT[5] * a[9][5] - iT[6] * a[8][0] + iT[18] * a[3][0] - iT[19] * a[6][5] - t[0] + add) >> shift);
    dst[20] = (short)CLIP(-32768, 32767, (iT[0] * a[8][2] - iT[11] * a[9][3] + iT[13] * a[6][3] - iT[24] * a[3][2] + iT[1] * a[0][1] + iT[10] * a[5][4] - iT[14] * a[6][4] - iT[23] * a[4][4] + iT[2] * a[1][5] + iT[9] * a[0][5] - iT[15] * a[2][5] - iT[22] * a[3][5] - iT[3] * a[9][2] + iT[8] * a[5][2] + iT[16] * a[2][3] + iT[21] * a[7][3] + iT[4] * a[5][5] - iT[7] * a[9][5] + iT[17] * a[7][0] + iT[20] * a[2][0] + iT[5] * a[0][4] + iT[6] * a[5][1] - iT[18] * a[6][1] - iT[19] * a[4][1] + t[0] + add) >> shift);
    dst[21] = (short)CLIP(-32768, 32767, (-iT[0] * a[2][1] - iT[11] * a[7][1] - iT[13] * a[5][4] + iT[24] * a[9][4] - iT[1] * a[6][2] - iT[10] * a[4][2] + iT[14] * a[5][2] + iT[23] * a[0][3] - iT[2] * a[2][4] - iT[9] * a[7][4] - iT[15] * a[5][1] + iT[22] * a[9][1] - iT[3] * a[6][5] - iT[8] * a[4][5] + iT[16] * a[5][5] + iT[21] * a[0][0] - iT[4] * a[4][0] - iT[7] * a[7][5] - iT[17] * a[1][5] + iT[20] * a[8][5] - iT[5] * a[7][2] - iT[6] * a[4][3] + iT[18] * a[8][2] - iT[19] * a[1][2] + t[1] + add) >> shift);
    dst[22] = (short)CLIP(-32768, 32767, (iT[0] * a[6][1] - iT[11] * a[3][4] - iT[13] * a[9][1] + iT[24] * a[8][4] + iT[1] * a[4][3] + iT[10] * a[6][3] - iT[14] * a[0][2] - iT[23] * a[5][3] + iT[2] * a[7][0] + iT[9] * a[4][5] - iT[15] * a[8][0] + iT[22] * a[1][0] - iT[3] * a[3][1] + iT[8] * a[6][4] + iT[16] * a[8][1] - iT[21] * a[9][4] - iT[4] * a[2][3] - iT[7] * a[3][3] + iT[17] * a[0][3] + iT[20] * a[1][3] - iT[5] * a[7][5] - iT[6] * a[2][5] + iT[18] * a[9][0] - iT[19] * a[5][0] + t[1] + add) >> shift);
    dst[23] = (short)CLIP(-32768, 32767, (-iT[0] * a[0][3] - iT[11] * a[1][3] + iT[13] * a[3][3] + iT[24] * a[2][3] - iT[1] * a[8][0] + iT[10] * a[9][5] - iT[14] * a[6][5] + iT[23] * a[3][0] + iT[2] * a[8][2] - iT[9] * a[1][2] - iT[15] * a[4][3] - iT[22] * a[7][2] + iT[3] * a[0][5] + iT[8] * a[5][0] - iT[16] * a[6][0] - iT[21] * a[4][0] + iT[4] * a[8][4] - iT[7] * a[9][1] + iT[17] * a[6][1] - iT[20] * a[3][4] - iT[5] * a[5][4] - iT[6] * a[0][1] + iT[18] * a[4][4] + iT[19] * a[6][4] + t[0] + add) >> shift);
    dst[26] = (short)CLIP(-32768, 32767, (-iT[0] * a[3][0] - iT[11] * a[2][0] + iT[13] * a[1][0] + iT[24] * a[0][0] - iT[1] * a[2][5] - iT[10] * a[3][5] + iT[14] * a[0][5] + iT[23] * a[1][5] + iT[2] * a[4][4] + iT[9] * a[6][4] - iT[15] * a[0][1] - iT[22] * a[5][4] - iT[3] * a[4][1] - iT[8] * a[7][4] - iT[16] * a[1][4] + iT[21] * a[8][4] + iT[4] * a[2][2] + iT[7] * a[7][2] + iT[17] * a[5][3] - iT[20] * a[9][3] + iT[5] * a[3][3] - iT[6] * a[6][2] - iT[18] * a[8][3] + iT[19] * a[9][2] - t[1] + add) >> shift);
    dst[27] = (short)CLIP(-32768, 32767, (-iT[0] * a[3][3] + iT[11] * a[6][2] + iT[13] * a[8][3] - iT[24] * a[9][2] - iT[1] * a[2][0] - iT[10] * a[3][0] + iT[14] * a[0][0] + iT[23] * a[1][0] - iT[2] * a[6][3] + iT[9] * a[3][2] + iT[15] * a[9][3] - iT[22] * a[8][2] - iT[3] * a[4][0] - iT[8] * a[6][0] + iT[16] * a[0][5] + iT[21] * a[5][0] - iT[4] * a[7][4] - iT[7] * a[2][4] + iT[17] * a[9][1] - iT[20] * a[5][1] - iT[5] * a[4][4] - iT[6] * a[7][1] - iT[18] * a[1][1] + iT[19] * a[8][1] - t[1] + add) >> shift);
    dst[28] = (short)CLIP(-32768, 32767, (iT[0] * a[0][4] + iT[11] * a[5][1] - iT[13] * a[6][1] - iT[24] * a[4][1] + iT[1] * a[9][3] - iT[10] * a[8][2] + iT[14] * a[3][2] - iT[23] * a[6][3] - iT[2] * a[1][0] - iT[9] * a[0][0] + iT[15] * a[2][0] + iT[22] * a[3][0] + iT[3] * a[8][1] - iT[8] * a[9][4] + iT[16] * a[6][4] - iT[21] * a[3][1] - iT[4] * a[5][2] - iT[7] * a[0][3] + iT[17] * a[4][2] + iT[20] * a[6][2] + iT[5] * a[1][5] - iT[6] * a[8][5] + iT[18] * a[7][5] + iT[19] * a[4][0] - t[0] + add) >> shift);
    dst[30] = (short)CLIP(-32768, 32767, (iT[0] * a[5][3] - iT[11] * a[9][3] + iT[13] * a[7][2] + iT[24] * a[2][2] + iT[1] * a[0][1] + iT[10] * a[1][1] - iT[14] * a[3][1] - iT[23] * a[2][1] + iT[2] * a[9][0] - iT[9] * a[5][0] - iT[15] * a[2][5] - iT[22] * a[7][5] - iT[3] * a[5][2] + iT[8] * a[9][2] - iT[16] * a[7][3] - iT[21] * a[2][3] - iT[4] * a[0][0] - iT[7] * a[1][0] + iT[17] * a[3][0] + iT[20] * a[2][0] - iT[5] * a[9][1] + iT[6] * a[5][1] + iT[18] * a[2][4] + iT[19] * a[7][4] + t[0] + add) >> shift);
    dst[31] = (short)CLIP(-32768, 32767, (iT[0] * a[3][5] + iT[11] * a[2][5] - iT[13] * a[1][5] - iT[24] * a[0][5] - iT[1] * a[3][4] - iT[10] * a[2][4] + iT[14] * a[1][4] + iT[23] * a[0][4] + iT[2] * a[3][3] + iT[9] * a[2][3] - iT[15] * a[1][3] - iT[22] * a[0][3] - iT[3] * a[3][2] - iT[8] * a[2][2] + iT[16] * a[1][2] + iT[21] * a[0][2] + iT[4] * a[3][1] + iT[7] * a[2][1] - iT[17] * a[1][1] - iT[20] * a[0][1] - iT[5] * a[3][0] - iT[6] * a[2][0] + iT[18] * a[1][0] + iT[19] * a[0][0] + t[1] + add) >> shift);

    dst[4] = (short)CLIP(-32768, 32767, (iT[4] * b[0] + iT[14] * b[1] + iT[24] * b[2] + iT[29] * b[3] + iT[19] * b[4] + iT[9] * b[5] + add) >> shift);
    dst[9] = (short)CLIP(-32768, 32767, (iT[9] * b[0] + iT[29] * b[1] + iT[14] * b[2] - iT[4] * b[3] - iT[24] * b[4] - iT[19] * b[5] + add) >> shift);
    dst[14] = (short)CLIP(-32768, 32767, (iT[14] * b[0] + iT[19] * b[1] - iT[9] * b[2] - iT[24] * b[3] + iT[4] * b[4] + iT[29] * b[5] + add) >> shift);
    dst[19] = (short)CLIP(-32768, 32767, (iT[19] * b[0] + iT[4] * b[1] - iT[29] * b[2] + iT[9] * b[3] + iT[14] * b[4] - iT[24] * b[5] + add) >> shift);
    dst[24] = (short)CLIP(-32768, 32767, (iT[24] * b[0] - iT[9] * b[1] - iT[4] * b[2] + iT[19] * b[3] - iT[29] * b[4] + iT[14] * b[5] + add) >> shift);
    dst[29] = (short)CLIP(-32768, 32767, (iT[29] * b[0] - iT[24] * b[1] + iT[19] * b[2] - iT[14] * b[3] + iT[9] * b[4] - iT[4] * b[5] + add) >> shift);

    dst[12] = (short)CLIP(-32768, 32767, (iT[12] * c[0] + iT[25] * c[1] + add) >> shift);
    dst[25] = (short)CLIP(-32768, 32767, (iT[25] * c[0] - iT[12] * c[1] + add) >> shift);
    src++;
    dst += 32;
  }

  if (skip_line)
  {
    memset(dst, 0, (skip_line * 32) * sizeof(int16_t));
  }
}


// ********************************** DCT-8 **********************************
static void fastForwardDCT8_B4(const int16_t *src, int16_t *dst, int32_t shift, int line, int skip_line, int skip_line2)
{
  int i;
  int rnd_factor = 1 << (shift - 1);
  const int16_t *iT = uvg_g_DCT8P4;

  int32_t c[4];
  int16_t *pCoeff = dst;
  const int  reduced_line = line - skip_line;
  for (i = 0; i < reduced_line; i++)
  {
    // Intermediate Variables
    c[0] = src[0] + src[3];
    c[1] = src[2] + src[0];
    c[2] = src[3] - src[2];
    c[3] = iT[1] * src[1];

    dst[0 * line] = (iT[3] * c[0] + iT[2] * c[1] + c[3] + rnd_factor) >> shift;
    dst[1 * line] = (iT[1] * (src[0] - src[2] - src[3]) + rnd_factor) >> shift;
    dst[2 * line] = (iT[3] * c[2] + iT[2] * c[0] - c[3] + rnd_factor) >> shift;
    dst[3 * line] = (iT[3] * c[1] - iT[2] * c[2] - c[3] + rnd_factor) >> shift;

    src += 4;
    dst++;
  }
  if (skip_line)
  {
    dst = pCoeff + reduced_line;
    for (i = 0; i < 4; i++)
    {
      memset(dst, 0, sizeof(int16_t)*skip_line);
      dst += line;
    }
  }
}

static void fastInverseDCT8_B4(const int16_t *src, int16_t *dst, int32_t shift, int line, int skip_line, int skip_line2)
{
  int i;
  int rnd_factor = 1 << (shift - 1);

  const int16_t *iT = uvg_g_DCT8P4;

  int32_t c[4];
  const int  reduced_line = line - skip_line;
  for (i = 0; i < reduced_line; i++)
  {
    // Intermediate Variables
    c[0] = src[0 * line] + src[3 * line];
    c[1] = src[2 * line] + src[0 * line];
    c[2] = src[3 * line] - src[2 * line];
    c[3] = iT[1] * src[1 * line];

    dst[0] = (short)CLIP(-32768, 32767, (iT[3] * c[0] + iT[2] * c[1] + c[3] + rnd_factor) >> shift);
    dst[1] = (short)CLIP(-32768, 32767, (iT[1] * (src[0 * line] - src[2 * line] - src[3 * line]) + rnd_factor) >> shift);
    dst[2] = (short)CLIP(-32768, 32767, (iT[3] * c[2] + iT[2] * c[0] - c[3] + rnd_factor) >> shift);
    dst[3] = (short)CLIP(-32768, 32767, (iT[3] * c[1] - iT[2] * c[2] - c[3] + rnd_factor) >> shift);
    dst += 4;
    src++;
  }
  if (skip_line)
  {
    memset(dst, 0, (skip_line << 2) * sizeof(int16_t));
  }
}

static void fastForwardDCT8_B16(const int16_t *src, int16_t *dst, int32_t shift, int line, int skip_line, int skip_line2)
{
  int j, k;
  int32_t a[5], b[5], c[5], d[5], t;
  int32_t add = (shift > 0) ? (1 << (shift - 1)) : 0;

  const int16_t *iT = uvg_g_DST7P16;

  int16_t *p_coef = dst;
  const int  reduced_line = line - skip_line;
  const int  cutoff = 16 - skip_line2;

  for (j = 0; j < reduced_line; j++)
  {
    for (k = 0; k < 5; k++)
    {
      a[k] = src[15 - k] + src[4 - k];
      b[k] = src[6 + k] + src[4 - k];
      c[k] = src[15 - k] - src[6 + k];
      d[k] = src[15 - k] + src[6 + k] - src[4 - k];
    }

    t = iT[10] * src[5];

    dst[1 * line] = (-iT[2] * d[0] - iT[5] * d[1] - iT[8] * d[2] - iT[11] * d[3] - iT[14] * d[4] + add) >> shift;
    dst[4 * line] = (iT[8] * d[0] + iT[14] * d[1] + iT[5] * d[2] - iT[2] * d[3] - iT[11] * d[4] + add) >> shift;
    dst[7 * line] = (-iT[14] * d[0] - iT[2] * d[1] + iT[11] * d[2] + iT[5] * d[3] - iT[8] * d[4] + add) >> shift;
    dst[10 * line] = (iT[11] * d[0] - iT[8] * d[1] - iT[2] * d[2] + iT[14] * d[3] - iT[5] * d[4] + add) >> shift;
    dst[13 * line] = (-iT[5] * d[0] + iT[11] * d[1] - iT[14] * d[2] + iT[8] * d[3] - iT[2] * d[4] + add) >> shift;

    dst[5 * line] = (-iT[10] * (src[15] + src[14] - src[12] - src[11] + src[9] + src[8] - src[6] - src[5] + src[3] + src[2] - src[0]) + add) >> shift;

    dst[0 * line] = (iT[0] * a[0] + iT[9] * b[0] + iT[1] * a[1] + iT[8] * b[1] + iT[2] * a[2] + iT[7] * b[2] + iT[3] * a[3] + iT[6] * b[3] + iT[4] * a[4] + iT[5] * b[4] + t + add) >> shift;
    dst[2 * line] = (iT[4] * c[0] - iT[5] * b[0] + iT[9] * c[1] - iT[0] * b[1] + iT[6] * c[2] + iT[3] * a[2] + iT[1] * c[3] + iT[8] * a[3] + iT[7] * a[4] + iT[2] * b[4] - t + add) >> shift;
    dst[3 * line] = (-iT[6] * a[0] - iT[3] * b[0] - iT[2] * c[1] - iT[7] * a[1] - iT[9] * c[2] - iT[0] * a[2] - iT[4] * c[3] + iT[5] * b[3] + iT[1] * a[4] + iT[8] * b[4] - t + add) >> shift;
    dst[6 * line] = (iT[8] * a[0] + iT[1] * c[0] + iT[6] * c[1] - iT[3] * b[1] - iT[5] * a[2] - iT[4] * b[2] - iT[7] * c[3] - iT[2] * a[3] - iT[0] * c[4] + iT[9] * b[4] + t + add) >> shift;
    dst[8 * line] = (iT[4] * c[0] + iT[5] * a[0] - iT[0] * c[1] + iT[9] * b[1] - iT[3] * c[2] - iT[6] * a[2] + iT[1] * c[3] - iT[8] * b[3] + iT[2] * c[4] + iT[7] * a[4] - t + add) >> shift;
    dst[9 * line] = (-iT[7] * c[0] - iT[2] * a[0] + iT[4] * a[1] + iT[5] * b[1] + iT[8] * c[2] - iT[1] * b[2] - iT[9] * a[3] - iT[0] * b[3] - iT[3] * c[4] + iT[6] * b[4] - t + add) >> shift;
    dst[11 * line] = (-iT[9] * a[0] - iT[0] * b[0] + iT[8] * c[1] + iT[1] * a[1] - iT[2] * c[2] + iT[7] * b[2] - iT[6] * a[3] - iT[3] * b[3] + iT[5] * c[4] + iT[4] * a[4] + t + add) >> shift;
    dst[12 * line] = (iT[7] * c[0] - iT[2] * b[0] - iT[5] * c[1] - iT[4] * a[1] + iT[8] * a[2] + iT[1] * b[2] - iT[0] * a[3] - iT[9] * b[3] - iT[6] * c[4] + iT[3] * b[4] + t + add) >> shift;
    dst[14 * line] = (iT[3] * a[0] + iT[6] * b[0] - iT[7] * a[1] - iT[2] * b[1] + iT[0] * c[2] + iT[9] * a[2] - iT[4] * c[3] - iT[5] * a[3] + iT[8] * c[4] + iT[1] * a[4] - t + add) >> shift;
    dst[15 * line] = (-iT[1] * c[0] + iT[8] * b[0] + iT[3] * c[1] - iT[6] * b[1] - iT[5] * c[2] + iT[4] * b[2] + iT[7] * c[3] - iT[2] * b[3] - iT[9] * c[4] + iT[0] * b[4] - t + add) >> shift;

    src += 16;
    dst++;
  }

  if (skip_line)
  {
    dst = p_coef + reduced_line;
    for (j = 0; j < cutoff; j++)
    {
      memset(dst, 0, sizeof(int16_t)*skip_line);
      dst += line;
    }
  }

  if (skip_line2)
  {
    dst = p_coef + line * cutoff;
    memset(dst, 0, sizeof(int16_t) * line * skip_line2);
  }
}

static void fastInverseDCT8_B16(const int16_t *src, int16_t *dst, int32_t shift, int line, int skip_line, int skip_line2)
{
  int j, k;
  int32_t a[5], b[5], c[5], d[5], t;

  int32_t add = (shift > 0) ? (1 << (shift - 1)) : 0;

  const int16_t *iT = uvg_g_DST7P16;

  const int reduced_line = line - skip_line;

  for (j = 0; j < reduced_line; j++)
  {
    for (k = 0; k < 5; k++)
    {
      a[k] = src[(15 - k) * line] + src[(4 - k) * line];
      b[k] = src[(6 + k) * line] + src[(4 - k) * line];
      c[k] = src[(15 - k) * line] - src[(6 + k) * line];
      d[k] = src[(15 - k) * line] + src[(6 + k) * line] - src[(4 - k) * line];
    }

    t = iT[10] * src[5 * line];

    dst[1] = (short)CLIP(-32768, 32767, (-iT[2] * d[0] - iT[5] * d[1] - iT[8] * d[2] - iT[11] * d[3] - iT[14] * d[4] + add) >> shift);
    dst[4] = (short)CLIP(-32768, 32767, (iT[8] * d[0] + iT[14] * d[1] + iT[5] * d[2] - iT[2] * d[3] - iT[11] * d[4] + add) >> shift);
    dst[7] = (short)CLIP(-32768, 32767, (-iT[14] * d[0] - iT[2] * d[1] + iT[11] * d[2] + iT[5] * d[3] - iT[8] * d[4] + add) >> shift);
    dst[10] = (short)CLIP(-32768, 32767, (iT[11] * d[0] - iT[8] * d[1] - iT[2] * d[2] + iT[14] * d[3] - iT[5] * d[4] + add) >> shift);
    dst[13] = (short)CLIP(-32768, 32767, (-iT[5] * d[0] + iT[11] * d[1] - iT[14] * d[2] + iT[8] * d[3] - iT[2] * d[4] + add) >> shift);

    dst[5] = (short)CLIP(-32768, 32767, (-iT[10] * (src[15 * line] + src[14 * line] - src[12 * line] - src[11 * line] + src[9 * line] + src[8 * line] - src[6 * line] - src[5 * line] + src[3 * line] + src[2 * line] - src[0 * line]) + add) >> shift);

    dst[0] = (short)CLIP(-32768, 32767, (iT[0] * a[0] + iT[9] * b[0] + iT[1] * a[1] + iT[8] * b[1] + iT[2] * a[2] + iT[7] * b[2] + iT[3] * a[3] + iT[6] * b[3] + iT[4] * a[4] + iT[5] * b[4] + t + add) >> shift);
    dst[2] = (short)CLIP(-32768, 32767, (iT[4] * c[0] - iT[5] * b[0] + iT[9] * c[1] - iT[0] * b[1] + iT[6] * c[2] + iT[3] * a[2] + iT[1] * c[3] + iT[8] * a[3] + iT[7] * a[4] + iT[2] * b[4] - t + add) >> shift);
    dst[3] = (short)CLIP(-32768, 32767, (-iT[6] * a[0] - iT[3] * b[0] - iT[2] * c[1] - iT[7] * a[1] - iT[9] * c[2] - iT[0] * a[2] - iT[4] * c[3] + iT[5] * b[3] + iT[1] * a[4] + iT[8] * b[4] - t + add) >> shift);
    dst[6] = (short)CLIP(-32768, 32767, (iT[8] * a[0] + iT[1] * c[0] + iT[6] * c[1] - iT[3] * b[1] - iT[5] * a[2] - iT[4] * b[2] - iT[7] * c[3] - iT[2] * a[3] - iT[0] * c[4] + iT[9] * b[4] + t + add) >> shift);
    dst[8] = (short)CLIP(-32768, 32767, (iT[4] * c[0] + iT[5] * a[0] - iT[0] * c[1] + iT[9] * b[1] - iT[3] * c[2] - iT[6] * a[2] + iT[1] * c[3] - iT[8] * b[3] + iT[2] * c[4] + iT[7] * a[4] - t + add) >> shift);
    dst[9] = (short)CLIP(-32768, 32767, (-iT[7] * c[0] - iT[2] * a[0] + iT[4] * a[1] + iT[5] * b[1] + iT[8] * c[2] - iT[1] * b[2] - iT[9] * a[3] - iT[0] * b[3] - iT[3] * c[4] + iT[6] * b[4] - t + add) >> shift);
    dst[11] = (short)CLIP(-32768, 32767, (-iT[9] * a[0] - iT[0] * b[0] + iT[8] * c[1] + iT[1] * a[1] - iT[2] * c[2] + iT[7] * b[2] - iT[6] * a[3] - iT[3] * b[3] + iT[5] * c[4] + iT[4] * a[4] + t + add) >> shift);
    dst[12] = (short)CLIP(-32768, 32767, (iT[7] * c[0] - iT[2] * b[0] - iT[5] * c[1] - iT[4] * a[1] + iT[8] * a[2] + iT[1] * b[2] - iT[0] * a[3] - iT[9] * b[3] - iT[6] * c[4] + iT[3] * b[4] + t + add) >> shift);
    dst[14] = (short)CLIP(-32768, 32767, (iT[3] * a[0] + iT[6] * b[0] - iT[7] * a[1] - iT[2] * b[1] + iT[0] * c[2] + iT[9] * a[2] - iT[4] * c[3] - iT[5] * a[3] + iT[8] * c[4] + iT[1] * a[4] - t + add) >> shift);
    dst[15] = (short)CLIP(-32768, 32767, (-iT[1] * c[0] + iT[8] * b[0] + iT[3] * c[1] - iT[6] * b[1] - iT[5] * c[2] + iT[4] * b[2] + iT[7] * c[3] - iT[2] * b[3] - iT[9] * c[4] + iT[0] * b[4] - t + add) >> shift);
    src++;
    dst += 16;
  }

  if (skip_line)
  {
    memset(dst, 0, (skip_line * 16) * sizeof(int16_t));
  }
}


static void fastForwardDCT8_B32(const int16_t *src, int16_t *dst, int32_t shift, int line, int skip_line, int skip_line2)
{
  int j, k;
  int32_t a[10][6];
  int32_t t[2];
  int32_t b[6];
  int32_t c[2];

  int32_t add = (shift > 0) ? (1 << (shift - 1)) : 0;
  const int16_t *iT = uvg_g_DST7P32;
  int16_t *p_coef = dst;
  const int  reduced_line = line - skip_line;
  const int  cutoff = 32 - skip_line2;

  for (j = 0; j < reduced_line; j++)
  {
    for (k = 0; k < 6; k++)
    {
      a[0][k] = src[31 - k] - src[20 + k];
      a[1][k] = src[31 - k] + src[18 - k];
      a[2][k] = src[31 - k] + src[7 + k];
      a[3][k] = src[31 - k] - src[5 - k];
      a[4][k] = src[25 - k] + src[13 + k];
      a[5][k] = src[25 - k] + src[12 - k];
      a[6][k] = src[25 - k] - src[k];
      a[7][k] = src[18 - k] - src[7 + k];
      a[8][k] = src[18 - k] + src[5 - k];
      a[9][k] = src[12 - k] + src[k];

      b[k] = src[31 - k] + src[20 + k] - src[18 - k] - src[7 + k] + src[5 - k];
    }

    for (k = 0; k < 2; k++)
    {
      c[k] = src[31 - k] + src[28 + k] - src[26 - k] - src[23 + k] + src[21 - k] + src[18 + k] - src[16 - k] - src[13 + k] + src[11 - k] + src[8 + k] - src[6 - k] - src[3 + k] + src[1 - k];
    }

    t[0] = iT[12] * src[19] + iT[25] * src[6];
    t[1] = iT[12] * src[6] - iT[25] * src[19];

    dst[0 * line] = (iT[0] * a[3][0] + iT[11] * a[6][5] + iT[13] * a[8][0] + iT[24] * a[9][5] + iT[1] * a[3][1] + iT[10] * a[6][4] + iT[14] * a[8][1] + iT[23] * a[9][4] + iT[2] * a[3][2] + iT[9] * a[6][3] + iT[15] * a[8][2] + iT[22] * a[9][3] + iT[3] * a[3][3] + iT[8] * a[6][2] + iT[16] * a[8][3] + iT[21] * a[9][2] + iT[4] * a[3][4] + iT[7] * a[6][1] + iT[17] * a[8][4] + iT[20] * a[9][1] + iT[5] * a[3][5] + iT[6] * a[6][0] + iT[18] * a[8][5] + iT[19] * a[9][0] + t[0] + add) >> shift;
    dst[1 * line] = (iT[0] * a[5][2] - iT[11] * a[0][3] - iT[13] * a[4][2] - iT[24] * a[6][2] - iT[1] * a[9][1] - iT[10] * a[8][4] - iT[14] * a[3][4] - iT[23] * a[6][1] - iT[2] * a[0][0] + iT[9] * a[5][5] - iT[15] * a[6][5] - iT[22] * a[4][5] + iT[3] * a[5][3] - iT[8] * a[0][2] - iT[16] * a[4][3] - iT[21] * a[6][3] - iT[4] * a[9][0] - iT[7] * a[8][5] - iT[17] * a[3][5] - iT[20] * a[6][0] - iT[5] * a[0][1] + iT[6] * a[5][4] - iT[18] * a[6][4] - iT[19] * a[4][4] + t[1] + add) >> shift;
    dst[3 * line] = (iT[0] * a[9][4] + iT[11] * a[5][4] - iT[13] * a[2][1] + iT[24] * a[7][1] + iT[1] * a[0][3] + iT[10] * a[1][3] - iT[14] * a[3][3] - iT[23] * a[2][3] - iT[2] * a[8][5] - iT[9] * a[9][0] - iT[15] * a[6][0] - iT[22] * a[3][5] + iT[3] * a[1][4] + iT[8] * a[0][4] - iT[16] * a[2][4] - iT[21] * a[3][4] + iT[4] * a[5][3] + iT[7] * a[9][3] + iT[17] * a[7][2] - iT[20] * a[2][2] - iT[5] * a[8][0] - iT[6] * a[1][0] + iT[18] * a[4][5] + iT[19] * a[7][0] - t[1] + add) >> shift;
    dst[4 * line] = (-iT[0] * a[3][2] - iT[11] * a[2][2] + iT[13] * a[1][2] + iT[24] * a[0][2] + iT[1] * a[6][0] + iT[10] * a[3][5] + iT[14] * a[9][0] + iT[23] * a[8][5] - iT[2] * a[2][3] - iT[9] * a[3][3] + iT[15] * a[0][3] + iT[22] * a[1][3] - iT[3] * a[7][0] + iT[8] * a[2][0] - iT[16] * a[9][5] - iT[21] * a[5][5] + iT[4] * a[4][4] + iT[7] * a[6][4] + iT[17] * a[0][1] - iT[20] * a[5][4] - iT[5] * a[7][4] - iT[6] * a[4][1] + iT[18] * a[8][4] + iT[19] * a[1][4] - t[0] + add) >> shift;
    dst[5 * line] = (iT[0] * a[3][5] + iT[11] * a[6][0] + iT[13] * a[8][5] + iT[24] * a[9][0] - iT[1] * a[6][5] - iT[10] * a[3][0] - iT[14] * a[9][5] - iT[23] * a[8][0] + iT[2] * a[7][4] - iT[9] * a[2][4] + iT[15] * a[9][1] + iT[22] * a[5][1] + iT[3] * a[7][1] + iT[8] * a[4][4] - iT[16] * a[8][1] - iT[21] * a[1][1] - iT[4] * a[6][2] - iT[7] * a[4][2] + iT[17] * a[5][2] - iT[20] * a[0][3] + iT[5] * a[3][2] + iT[6] * a[2][2] - iT[18] * a[1][2] - iT[19] * a[0][2] - t[0] + add) >> shift;
    dst[8 * line] = (iT[0] * a[9][3] + iT[11] * a[8][2] + iT[13] * a[3][2] + iT[24] * a[6][3] + iT[1] * a[1][5] + iT[10] * a[0][5] - iT[14] * a[2][5] - iT[23] * a[3][5] - iT[2] * a[1][3] - iT[9] * a[8][3] + iT[15] * a[7][3] + iT[22] * a[4][2] - iT[3] * a[9][5] - iT[8] * a[5][5] + iT[16] * a[2][0] - iT[21] * a[7][0] - iT[4] * a[1][1] - iT[7] * a[0][1] + iT[17] * a[2][1] + iT[20] * a[3][1] + iT[5] * a[5][1] + iT[6] * a[9][1] + iT[18] * a[7][4] - iT[19] * a[2][4] + t[1] + add) >> shift;
    dst[9 * line] = (iT[0] * a[2][1] + iT[11] * a[3][1] - iT[13] * a[0][1] - iT[24] * a[1][1] - iT[1] * a[7][3] + iT[10] * a[2][3] - iT[14] * a[9][2] - iT[23] * a[5][2] - iT[2] * a[4][0] - iT[9] * a[7][5] + iT[15] * a[1][5] + iT[22] * a[8][5] - iT[3] * a[3][4] - iT[8] * a[2][4] + iT[16] * a[1][4] + iT[21] * a[0][4] - iT[4] * a[6][3] - iT[7] * a[3][2] - iT[17] * a[9][3] - iT[20] * a[8][2] - iT[5] * a[4][5] - iT[6] * a[6][5] - iT[18] * a[0][0] + iT[19] * a[5][5] + t[0] + add) >> shift;
    dst[10 * line] = (-iT[0] * a[6][1] - iT[11] * a[4][1] + iT[13] * a[5][1] - iT[24] * a[0][4] + iT[1] * a[2][2] - iT[10] * a[7][2] - iT[14] * a[5][3] - iT[23] * a[9][3] + iT[2] * a[6][4] + iT[9] * a[4][4] - iT[15] * a[5][4] + iT[22] * a[0][1] - iT[3] * a[2][5] + iT[8] * a[7][5] + iT[16] * a[5][0] + iT[21] * a[9][0] - iT[4] * a[7][0] - iT[7] * a[4][5] + iT[17] * a[8][0] + iT[20] * a[1][0] + iT[5] * a[4][2] + iT[6] * a[7][3] - iT[18] * a[1][3] - iT[19] * a[8][3] + t[0] + add) >> shift;
    dst[11 * line] = (-iT[0] * a[1][3] - iT[11] * a[0][3] + iT[13] * a[2][3] + iT[24] * a[3][3] - iT[1] * a[9][1] - iT[10] * a[5][1] + iT[14] * a[2][4] - iT[23] * a[7][4] - iT[2] * a[8][0] - iT[9] * a[9][5] - iT[15] * a[6][5] - iT[22] * a[3][0] + iT[3] * a[0][2] - iT[8] * a[5][3] + iT[16] * a[6][3] + iT[21] * a[4][3] + iT[4] * a[5][0] - iT[7] * a[0][5] - iT[17] * a[4][0] - iT[20] * a[6][0] + iT[5] * a[9][4] + iT[6] * a[5][4] - iT[18] * a[2][1] + iT[19] * a[7][1] + t[1] + add) >> shift;
    dst[13 * line] = (iT[0] * a[0][0] + iT[11] * a[1][0] - iT[13] * a[3][0] - iT[24] * a[2][0] + iT[1] * a[5][4] - iT[10] * a[0][1] - iT[14] * a[4][4] - iT[23] * a[6][4] - iT[2] * a[9][3] - iT[9] * a[5][3] + iT[15] * a[2][2] - iT[22] * a[7][2] + iT[3] * a[8][3] + iT[8] * a[9][2] + iT[16] * a[6][2] + iT[21] * a[3][3] - iT[4] * a[1][4] - iT[7] * a[8][4] + iT[17] * a[7][4] + iT[20] * a[4][1] + iT[5] * a[0][5] + iT[6] * a[1][5] - iT[18] * a[3][5] - iT[19] * a[2][5] - t[1] + add) >> shift;
    dst[14 * line] = (iT[0] * a[4][2] + iT[11] * a[7][3] - iT[13] * a[1][3] - iT[24] * a[8][3] + iT[1] * a[4][1] + iT[10] * a[6][1] + iT[14] * a[0][4] - iT[23] * a[5][1] - iT[2] * a[3][0] - iT[9] * a[2][0] + iT[15] * a[1][0] + iT[22] * a[0][0] - iT[3] * a[6][3] - iT[8] * a[4][3] + iT[16] * a[5][3] - iT[21] * a[0][2] - iT[4] * a[7][5] - iT[7] * a[4][0] + iT[17] * a[8][5] + iT[20] * a[1][5] + iT[5] * a[6][4] + iT[6] * a[3][1] + iT[18] * a[9][4] + iT[19] * a[8][1] - t[0] + add) >> shift;
    dst[15 * line] = (iT[0] * a[7][4] + iT[11] * a[4][1] - iT[13] * a[8][4] - iT[24] * a[1][4] - iT[1] * a[2][2] - iT[10] * a[3][2] + iT[14] * a[0][2] + iT[23] * a[1][2] - iT[2] * a[2][1] + iT[9] * a[7][1] + iT[15] * a[5][4] + iT[22] * a[9][4] + iT[3] * a[7][5] - iT[8] * a[2][5] + iT[16] * a[9][0] + iT[21] * a[5][0] + iT[4] * a[2][0] + iT[7] * a[3][0] - iT[17] * a[0][0] - iT[20] * a[1][0] + iT[5] * a[2][3] - iT[6] * a[7][3] - iT[18] * a[5][2] - iT[19] * a[9][2] - t[0] + add) >> shift;
    dst[16 * line] = (-iT[0] * a[0][1] + iT[11] * a[5][4] - iT[13] * a[6][4] - iT[24] * a[4][4] + iT[1] * a[0][3] - iT[10] * a[5][2] + iT[14] * a[6][2] + iT[23] * a[4][2] - iT[2] * a[0][5] + iT[9] * a[5][0] - iT[15] * a[6][0] - iT[22] * a[4][0] - iT[3] * a[0][4] - iT[8] * a[1][4] + iT[16] * a[3][4] + iT[21] * a[2][4] + iT[4] * a[0][2] + iT[7] * a[1][2] - iT[17] * a[3][2] - iT[20] * a[2][2] - iT[5] * a[0][0] - iT[6] * a[1][0] + iT[18] * a[3][0] + iT[19] * a[2][0] - t[1] + add) >> shift;
    dst[18 * line] = (iT[0] * a[0][5] + iT[11] * a[1][5] - iT[13] * a[3][5] - iT[24] * a[2][5] - iT[1] * a[1][0] - iT[10] * a[0][0] + iT[14] * a[2][0] + iT[23] * a[3][0] - iT[2] * a[5][1] + iT[9] * a[0][4] + iT[15] * a[4][1] + iT[22] * a[6][1] - iT[3] * a[8][1] - iT[8] * a[1][1] + iT[16] * a[4][4] + iT[21] * a[7][1] - iT[4] * a[9][2] - iT[7] * a[5][2] + iT[17] * a[2][3] - iT[20] * a[7][3] - iT[5] * a[9][3] - iT[6] * a[8][2] - iT[18] * a[3][2] - iT[19] * a[6][3] + t[1] + add) >> shift;
    dst[20 * line] = (-iT[0] * a[4][0] - iT[11] * a[6][0] - iT[13] * a[0][5] + iT[24] * a[5][0] + iT[1] * a[6][5] + iT[10] * a[4][5] - iT[14] * a[5][5] + iT[23] * a[0][0] - iT[2] * a[6][1] - iT[9] * a[3][4] - iT[15] * a[9][1] - iT[22] * a[8][4] + iT[3] * a[4][4] + iT[8] * a[7][1] - iT[16] * a[1][1] - iT[21] * a[8][1] - iT[4] * a[3][3] - iT[7] * a[2][3] + iT[17] * a[1][3] + iT[20] * a[0][3] + iT[5] * a[7][2] - iT[6] * a[2][2] + iT[18] * a[9][3] + iT[19] * a[5][3] + t[0] + add) >> shift;
    dst[21 * line] = (iT[0] * a[1][2] + iT[11] * a[8][2] - iT[13] * a[7][2] - iT[24] * a[4][3] + iT[1] * a[1][5] + iT[10] * a[8][5] - iT[14] * a[7][5] - iT[23] * a[4][0] + iT[2] * a[5][2] + iT[9] * a[9][2] + iT[15] * a[7][3] - iT[22] * a[2][3] + iT[3] * a[5][5] + iT[8] * a[9][5] + iT[16] * a[7][0] - iT[21] * a[2][0] + iT[4] * a[8][1] + iT[7] * a[9][4] + iT[17] * a[6][4] + iT[20] * a[3][1] + iT[5] * a[8][4] + iT[6] * a[9][1] + iT[18] * a[6][1] + iT[19] * a[3][4] + t[1] + add) >> shift;
    dst[23 * line] = (iT[0] * a[8][4] + iT[11] * a[9][1] + iT[13] * a[6][1] + iT[24] * a[3][4] - iT[1] * a[8][2] - iT[10] * a[1][2] + iT[14] * a[4][3] + iT[23] * a[7][2] - iT[2] * a[0][1] - iT[9] * a[1][1] + iT[15] * a[3][1] + iT[22] * a[2][1] + iT[3] * a[5][0] + iT[8] * a[9][0] + iT[16] * a[7][5] - iT[21] * a[2][5] - iT[4] * a[9][5] - iT[7] * a[8][0] - iT[17] * a[3][0] - iT[20] * a[6][5] + iT[5] * a[5][2] - iT[6] * a[0][3] - iT[18] * a[4][2] - iT[19] * a[6][2] - t[1] + add) >> shift;
    dst[24 * line] = (-iT[0] * a[2][3] + iT[11] * a[7][3] + iT[13] * a[5][2] + iT[24] * a[9][2] + iT[1] * a[4][1] + iT[10] * a[7][4] - iT[14] * a[1][4] - iT[23] * a[8][4] - iT[2] * a[4][5] - iT[9] * a[7][0] + iT[15] * a[1][0] + iT[22] * a[8][0] + iT[3] * a[4][3] + iT[8] * a[6][3] + iT[16] * a[0][2] - iT[21] * a[5][3] - iT[4] * a[2][5] - iT[7] * a[3][5] + iT[17] * a[0][5] + iT[20] * a[1][5] + iT[5] * a[2][1] + iT[6] * a[3][1] - iT[18] * a[0][1] - iT[19] * a[1][1] - t[0] + add) >> shift;
    dst[25 * line] = (-iT[0] * a[4][5] - iT[11] * a[6][5] - iT[13] * a[0][0] + iT[24] * a[5][5] - iT[1] * a[3][1] - iT[10] * a[2][1] + iT[14] * a[1][1] + iT[23] * a[0][1] + iT[2] * a[7][2] + iT[9] * a[4][3] - iT[15] * a[8][2] - iT[22] * a[1][2] + iT[3] * a[6][2] + iT[8] * a[3][3] + iT[16] * a[9][2] + iT[21] * a[8][3] + iT[4] * a[2][4] - iT[7] * a[7][4] - iT[17] * a[5][1] - iT[20] * a[9][1] - iT[5] * a[4][0] - iT[6] * a[6][0] - iT[18] * a[0][5] + iT[19] * a[5][0] - t[0] + add) >> shift;
    dst[26 * line] = (iT[0] * a[8][0] + iT[11] * a[1][0] - iT[13] * a[4][5] - iT[24] * a[7][0] + iT[1] * a[5][4] + iT[10] * a[9][4] + iT[14] * a[7][1] - iT[23] * a[2][1] - iT[2] * a[1][2] - iT[9] * a[0][2] + iT[15] * a[2][2] + iT[22] * a[3][2] - iT[3] * a[9][2] - iT[8] * a[8][3] - iT[16] * a[3][3] - iT[21] * a[6][2] + iT[4] * a[0][4] - iT[7] * a[5][1] + iT[17] * a[6][1] + iT[20] * a[4][1] + iT[5] * a[8][5] + iT[6] * a[1][5] - iT[18] * a[4][0] - iT[19] * a[7][5] - t[1] + add) >> shift;
    dst[28 * line] = (-iT[0] * a[5][1] - iT[11] * a[9][1] - iT[13] * a[7][4] + iT[24] * a[2][4] + iT[1] * a[8][2] + iT[10] * a[9][3] + iT[14] * a[6][3] + iT[23] * a[3][2] - iT[2] * a[9][4] - iT[9] * a[8][1] - iT[15] * a[3][1] - iT[22] * a[6][4] + iT[3] * a[9][0] + iT[8] * a[5][0] - iT[16] * a[2][5] + iT[21] * a[7][5] - iT[4] * a[5][5] + iT[7] * a[0][0] + iT[17] * a[4][5] + iT[20] * a[6][5] + iT[5] * a[1][3] + iT[6] * a[0][3] - iT[18] * a[2][3] - iT[19] * a[3][3] + t[1] + add) >> shift;
    dst[29 * line] = (iT[0] * a[6][4] + iT[11] * a[3][1] + iT[13] * a[9][4] + iT[24] * a[8][1] - iT[1] * a[7][3] - iT[10] * a[4][2] + iT[14] * a[8][3] + iT[23] * a[1][3] - iT[2] * a[3][5] - iT[9] * a[2][5] + iT[15] * a[1][5] + iT[22] * a[0][5] + iT[3] * a[2][4] + iT[8] * a[3][4] - iT[16] * a[0][4] - iT[21] * a[1][4] + iT[4] * a[4][3] + iT[7] * a[7][2] - iT[17] * a[1][2] - iT[20] * a[8][2] - iT[5] * a[3][0] - iT[6] * a[6][5] - iT[18] * a[8][0] - iT[19] * a[9][5] + t[0] + add) >> shift;
    dst[30 * line] = (-iT[0] * a[7][2] + iT[11] * a[2][2] - iT[13] * a[9][3] - iT[24] * a[5][3] - iT[1] * a[6][0] - iT[10] * a[4][0] + iT[14] * a[5][0] - iT[23] * a[0][5] - iT[2] * a[4][2] - iT[9] * a[6][2] - iT[15] * a[0][3] + iT[22] * a[5][2] + iT[3] * a[2][0] - iT[8] * a[7][0] - iT[16] * a[5][5] - iT[21] * a[9][5] + iT[4] * a[7][1] - iT[7] * a[2][1] + iT[17] * a[9][4] + iT[20] * a[5][4] + iT[5] * a[6][1] + iT[6] * a[4][1] - iT[18] * a[5][1] + iT[19] * a[0][4] + t[0] + add) >> shift;
    dst[31 * line] = (iT[0] * a[8][5] + iT[11] * a[1][5] - iT[13] * a[4][0] - iT[24] * a[7][5] - iT[1] * a[1][0] - iT[10] * a[8][0] + iT[14] * a[7][0] + iT[23] * a[4][5] - iT[2] * a[8][4] - iT[9] * a[1][4] + iT[15] * a[4][1] + iT[22] * a[7][4] + iT[3] * a[1][1] + iT[8] * a[8][1] - iT[16] * a[7][1] - iT[21] * a[4][4] + iT[4] * a[8][3] + iT[7] * a[1][3] - iT[17] * a[4][2] - iT[20] * a[7][3] - iT[5] * a[1][2] - iT[6] * a[8][2] + iT[18] * a[7][2] + iT[19] * a[4][3] + t[1] + add) >> shift;

    dst[2 * line] = (iT[4] * b[0] + iT[9] * b[1] + iT[14] * b[2] + iT[19] * b[3] + iT[24] * b[4] + iT[29] * b[5] + add) >> shift;
    dst[7 * line] = (-iT[14] * b[0] - iT[29] * b[1] - iT[19] * b[2] - iT[4] * b[3] + iT[9] * b[4] + iT[24] * b[5] + add) >> shift;
    dst[12 * line] = (iT[24] * b[0] + iT[14] * b[1] - iT[9] * b[2] - iT[29] * b[3] - iT[4] * b[4] + iT[19] * b[5] + add) >> shift;
    dst[17 * line] = (-iT[29] * b[0] + iT[4] * b[1] + iT[24] * b[2] - iT[9] * b[3] - iT[19] * b[4] + iT[14] * b[5] + add) >> shift;
    dst[22 * line] = (iT[19] * b[0] - iT[24] * b[1] + iT[4] * b[2] + iT[14] * b[3] - iT[29] * b[4] + iT[9] * b[5] + add) >> shift;
    dst[27 * line] = (-iT[9] * b[0] + iT[19] * b[1] - iT[29] * b[2] + iT[24] * b[3] - iT[14] * b[4] + iT[4] * b[5] + add) >> shift;

    dst[6 * line] = (iT[12] * c[0] + iT[25] * c[1] + add) >> shift;
    dst[19 * line] = (-iT[25] * c[0] + iT[12] * c[1] + add) >> shift;

    src += 32;
    dst++;
  }

  if (skip_line)
  {
    dst = p_coef + reduced_line;
    for (j = 0; j < cutoff; j++)
    {
      memset(dst, 0, sizeof(int16_t)*skip_line);
      dst += line;
    }
  }

  if (skip_line2)
  {
    dst = p_coef + line * cutoff;
    memset(dst, 0, sizeof(int16_t) * line * skip_line2);
  }
}

static void fastInverseDCT8_B32(const int16_t *src, int16_t *dst, int32_t shift, int line, int skip_line, int skip_line2)
{
  int j, k;
  int32_t a[10][6];
  int32_t t[2];
  int32_t b[6];
  int32_t c[2];
  int32_t add = (shift > 0) ? (1 << (shift - 1)) : 0;

  const int16_t *iT = uvg_g_DST7P32;

  const int  reduced_line = line - skip_line;

  for (j = 0; j < reduced_line; j++)
  {
    for (k = 0; k < 6; k++)
    {
      a[0][k] = src[(31 - k)*line] - src[(20 + k)*line];
      a[1][k] = src[(31 - k)*line] + src[(18 - k)*line];
      a[2][k] = src[(31 - k)*line] + src[(7 + k)*line];
      a[3][k] = src[(31 - k)*line] - src[(5 - k)*line];
      a[4][k] = src[(25 - k)*line] + src[(13 + k)*line];
      a[5][k] = src[(25 - k)*line] + src[(12 - k)*line];
      a[6][k] = src[(25 - k)*line] - src[k *line];
      a[7][k] = src[(18 - k)*line] - src[(7 + k)*line];
      a[8][k] = src[(18 - k)*line] + src[(5 - k)*line];
      a[9][k] = src[(12 - k)*line] + src[k *line];

      b[k] = src[(31 - k)*line] + src[(20 + k)*line] - src[(18 - k)*line] - src[(7 + k)*line] + src[(5 - k)*line];
    }

    for (k = 0; k < 2; k++)
    {
      c[k] = src[(31 - k)*line] + src[(28 + k)*line] - src[(26 - k)*line] - src[(23 + k)*line] + src[(21 - k)*line] + src[(18 + k)*line] - src[(16 - k)*line] - src[(13 + k)*line] + src[(11 - k)*line] + src[(8 + k)*line] - src[(6 - k)*line] - src[(3 + k)*line] + src[(1 - k)*line];
    }

    t[0] = iT[12] * src[19 * line] + iT[25] * src[6 * line];
    t[1] = iT[12] * src[6 * line] - iT[25] * src[19 * line];

    dst[0] = (short)CLIP(-32768, 32767, (iT[0] * a[3][0] + iT[11] * a[6][5] + iT[13] * a[8][0] + iT[24] * a[9][5] + iT[1] * a[3][1] + iT[10] * a[6][4] + iT[14] * a[8][1] + iT[23] * a[9][4] + iT[2] * a[3][2] + iT[9] * a[6][3] + iT[15] * a[8][2] + iT[22] * a[9][3] + iT[3] * a[3][3] + iT[8] * a[6][2] + iT[16] * a[8][3] + iT[21] * a[9][2] + iT[4] * a[3][4] + iT[7] * a[6][1] + iT[17] * a[8][4] + iT[20] * a[9][1] + iT[5] * a[3][5] + iT[6] * a[6][0] + iT[18] * a[8][5] + iT[19] * a[9][0] + t[0] + add) >> shift);
    dst[1] = (short)CLIP(-32768, 32767, (iT[0] * a[5][2] - iT[11] * a[0][3] - iT[13] * a[4][2] - iT[24] * a[6][2] - iT[1] * a[9][1] - iT[10] * a[8][4] - iT[14] * a[3][4] - iT[23] * a[6][1] - iT[2] * a[0][0] + iT[9] * a[5][5] - iT[15] * a[6][5] - iT[22] * a[4][5] + iT[3] * a[5][3] - iT[8] * a[0][2] - iT[16] * a[4][3] - iT[21] * a[6][3] - iT[4] * a[9][0] - iT[7] * a[8][5] - iT[17] * a[3][5] - iT[20] * a[6][0] - iT[5] * a[0][1] + iT[6] * a[5][4] - iT[18] * a[6][4] - iT[19] * a[4][4] + t[1] + add) >> shift);
    dst[3] = (short)CLIP(-32768, 32767, (iT[0] * a[9][4] + iT[11] * a[5][4] - iT[13] * a[2][1] + iT[24] * a[7][1] + iT[1] * a[0][3] + iT[10] * a[1][3] - iT[14] * a[3][3] - iT[23] * a[2][3] - iT[2] * a[8][5] - iT[9] * a[9][0] - iT[15] * a[6][0] - iT[22] * a[3][5] + iT[3] * a[1][4] + iT[8] * a[0][4] - iT[16] * a[2][4] - iT[21] * a[3][4] + iT[4] * a[5][3] + iT[7] * a[9][3] + iT[17] * a[7][2] - iT[20] * a[2][2] - iT[5] * a[8][0] - iT[6] * a[1][0] + iT[18] * a[4][5] + iT[19] * a[7][0] - t[1] + add) >> shift);
    dst[4] = (short)CLIP(-32768, 32767, (-iT[0] * a[3][2] - iT[11] * a[2][2] + iT[13] * a[1][2] + iT[24] * a[0][2] + iT[1] * a[6][0] + iT[10] * a[3][5] + iT[14] * a[9][0] + iT[23] * a[8][5] - iT[2] * a[2][3] - iT[9] * a[3][3] + iT[15] * a[0][3] + iT[22] * a[1][3] - iT[3] * a[7][0] + iT[8] * a[2][0] - iT[16] * a[9][5] - iT[21] * a[5][5] + iT[4] * a[4][4] + iT[7] * a[6][4] + iT[17] * a[0][1] - iT[20] * a[5][4] - iT[5] * a[7][4] - iT[6] * a[4][1] + iT[18] * a[8][4] + iT[19] * a[1][4] - t[0] + add) >> shift);
    dst[5] = (short)CLIP(-32768, 32767, (iT[0] * a[3][5] + iT[11] * a[6][0] + iT[13] * a[8][5] + iT[24] * a[9][0] - iT[1] * a[6][5] - iT[10] * a[3][0] - iT[14] * a[9][5] - iT[23] * a[8][0] + iT[2] * a[7][4] - iT[9] * a[2][4] + iT[15] * a[9][1] + iT[22] * a[5][1] + iT[3] * a[7][1] + iT[8] * a[4][4] - iT[16] * a[8][1] - iT[21] * a[1][1] - iT[4] * a[6][2] - iT[7] * a[4][2] + iT[17] * a[5][2] - iT[20] * a[0][3] + iT[5] * a[3][2] + iT[6] * a[2][2] - iT[18] * a[1][2] - iT[19] * a[0][2] - t[0] + add) >> shift);
    dst[8] = (short)CLIP(-32768, 32767, (iT[0] * a[9][3] + iT[11] * a[8][2] + iT[13] * a[3][2] + iT[24] * a[6][3] + iT[1] * a[1][5] + iT[10] * a[0][5] - iT[14] * a[2][5] - iT[23] * a[3][5] - iT[2] * a[1][3] - iT[9] * a[8][3] + iT[15] * a[7][3] + iT[22] * a[4][2] - iT[3] * a[9][5] - iT[8] * a[5][5] + iT[16] * a[2][0] - iT[21] * a[7][0] - iT[4] * a[1][1] - iT[7] * a[0][1] + iT[17] * a[2][1] + iT[20] * a[3][1] + iT[5] * a[5][1] + iT[6] * a[9][1] + iT[18] * a[7][4] - iT[19] * a[2][4] + t[1] + add) >> shift);
    dst[9] = (short)CLIP(-32768, 32767, (iT[0] * a[2][1] + iT[11] * a[3][1] - iT[13] * a[0][1] - iT[24] * a[1][1] - iT[1] * a[7][3] + iT[10] * a[2][3] - iT[14] * a[9][2] - iT[23] * a[5][2] - iT[2] * a[4][0] - iT[9] * a[7][5] + iT[15] * a[1][5] + iT[22] * a[8][5] - iT[3] * a[3][4] - iT[8] * a[2][4] + iT[16] * a[1][4] + iT[21] * a[0][4] - iT[4] * a[6][3] - iT[7] * a[3][2] - iT[17] * a[9][3] - iT[20] * a[8][2] - iT[5] * a[4][5] - iT[6] * a[6][5] - iT[18] * a[0][0] + iT[19] * a[5][5] + t[0] + add) >> shift);
    dst[10] = (short)CLIP(-32768, 32767, (-iT[0] * a[6][1] - iT[11] * a[4][1] + iT[13] * a[5][1] - iT[24] * a[0][4] + iT[1] * a[2][2] - iT[10] * a[7][2] - iT[14] * a[5][3] - iT[23] * a[9][3] + iT[2] * a[6][4] + iT[9] * a[4][4] - iT[15] * a[5][4] + iT[22] * a[0][1] - iT[3] * a[2][5] + iT[8] * a[7][5] + iT[16] * a[5][0] + iT[21] * a[9][0] - iT[4] * a[7][0] - iT[7] * a[4][5] + iT[17] * a[8][0] + iT[20] * a[1][0] + iT[5] * a[4][2] + iT[6] * a[7][3] - iT[18] * a[1][3] - iT[19] * a[8][3] + t[0] + add) >> shift);
    dst[11] = (short)CLIP(-32768, 32767, (-iT[0] * a[1][3] - iT[11] * a[0][3] + iT[13] * a[2][3] + iT[24] * a[3][3] - iT[1] * a[9][1] - iT[10] * a[5][1] + iT[14] * a[2][4] - iT[23] * a[7][4] - iT[2] * a[8][0] - iT[9] * a[9][5] - iT[15] * a[6][5] - iT[22] * a[3][0] + iT[3] * a[0][2] - iT[8] * a[5][3] + iT[16] * a[6][3] + iT[21] * a[4][3] + iT[4] * a[5][0] - iT[7] * a[0][5] - iT[17] * a[4][0] - iT[20] * a[6][0] + iT[5] * a[9][4] + iT[6] * a[5][4] - iT[18] * a[2][1] + iT[19] * a[7][1] + t[1] + add) >> shift);
    dst[13] = (short)CLIP(-32768, 32767, (iT[0] * a[0][0] + iT[11] * a[1][0] - iT[13] * a[3][0] - iT[24] * a[2][0] + iT[1] * a[5][4] - iT[10] * a[0][1] - iT[14] * a[4][4] - iT[23] * a[6][4] - iT[2] * a[9][3] - iT[9] * a[5][3] + iT[15] * a[2][2] - iT[22] * a[7][2] + iT[3] * a[8][3] + iT[8] * a[9][2] + iT[16] * a[6][2] + iT[21] * a[3][3] - iT[4] * a[1][4] - iT[7] * a[8][4] + iT[17] * a[7][4] + iT[20] * a[4][1] + iT[5] * a[0][5] + iT[6] * a[1][5] - iT[18] * a[3][5] - iT[19] * a[2][5] - t[1] + add) >> shift);
    dst[14] = (short)CLIP(-32768, 32767, (iT[0] * a[4][2] + iT[11] * a[7][3] - iT[13] * a[1][3] - iT[24] * a[8][3] + iT[1] * a[4][1] + iT[10] * a[6][1] + iT[14] * a[0][4] - iT[23] * a[5][1] - iT[2] * a[3][0] - iT[9] * a[2][0] + iT[15] * a[1][0] + iT[22] * a[0][0] - iT[3] * a[6][3] - iT[8] * a[4][3] + iT[16] * a[5][3] - iT[21] * a[0][2] - iT[4] * a[7][5] - iT[7] * a[4][0] + iT[17] * a[8][5] + iT[20] * a[1][5] + iT[5] * a[6][4] + iT[6] * a[3][1] + iT[18] * a[9][4] + iT[19] * a[8][1] - t[0] + add) >> shift);
    dst[15] = (short)CLIP(-32768, 32767, (iT[0] * a[7][4] + iT[11] * a[4][1] - iT[13] * a[8][4] - iT[24] * a[1][4] - iT[1] * a[2][2] - iT[10] * a[3][2] + iT[14] * a[0][2] + iT[23] * a[1][2] - iT[2] * a[2][1] + iT[9] * a[7][1] + iT[15] * a[5][4] + iT[22] * a[9][4] + iT[3] * a[7][5] - iT[8] * a[2][5] + iT[16] * a[9][0] + iT[21] * a[5][0] + iT[4] * a[2][0] + iT[7] * a[3][0] - iT[17] * a[0][0] - iT[20] * a[1][0] + iT[5] * a[2][3] - iT[6] * a[7][3] - iT[18] * a[5][2] - iT[19] * a[9][2] - t[0] + add) >> shift);
    dst[16] = (short)CLIP(-32768, 32767, (-iT[0] * a[0][1] + iT[11] * a[5][4] - iT[13] * a[6][4] - iT[24] * a[4][4] + iT[1] * a[0][3] - iT[10] * a[5][2] + iT[14] * a[6][2] + iT[23] * a[4][2] - iT[2] * a[0][5] + iT[9] * a[5][0] - iT[15] * a[6][0] - iT[22] * a[4][0] - iT[3] * a[0][4] - iT[8] * a[1][4] + iT[16] * a[3][4] + iT[21] * a[2][4] + iT[4] * a[0][2] + iT[7] * a[1][2] - iT[17] * a[3][2] - iT[20] * a[2][2] - iT[5] * a[0][0] - iT[6] * a[1][0] + iT[18] * a[3][0] + iT[19] * a[2][0] - t[1] + add) >> shift);
    dst[18] = (short)CLIP(-32768, 32767, (iT[0] * a[0][5] + iT[11] * a[1][5] - iT[13] * a[3][5] - iT[24] * a[2][5] - iT[1] * a[1][0] - iT[10] * a[0][0] + iT[14] * a[2][0] + iT[23] * a[3][0] - iT[2] * a[5][1] + iT[9] * a[0][4] + iT[15] * a[4][1] + iT[22] * a[6][1] - iT[3] * a[8][1] - iT[8] * a[1][1] + iT[16] * a[4][4] + iT[21] * a[7][1] - iT[4] * a[9][2] - iT[7] * a[5][2] + iT[17] * a[2][3] - iT[20] * a[7][3] - iT[5] * a[9][3] - iT[6] * a[8][2] - iT[18] * a[3][2] - iT[19] * a[6][3] + t[1] + add) >> shift);
    dst[20] = (short)CLIP(-32768, 32767, (-iT[0] * a[4][0] - iT[11] * a[6][0] - iT[13] * a[0][5] + iT[24] * a[5][0] + iT[1] * a[6][5] + iT[10] * a[4][5] - iT[14] * a[5][5] + iT[23] * a[0][0] - iT[2] * a[6][1] - iT[9] * a[3][4] - iT[15] * a[9][1] - iT[22] * a[8][4] + iT[3] * a[4][4] + iT[8] * a[7][1] - iT[16] * a[1][1] - iT[21] * a[8][1] - iT[4] * a[3][3] - iT[7] * a[2][3] + iT[17] * a[1][3] + iT[20] * a[0][3] + iT[5] * a[7][2] - iT[6] * a[2][2] + iT[18] * a[9][3] + iT[19] * a[5][3] + t[0] + add) >> shift);
    dst[21] = (short)CLIP(-32768, 32767, (iT[0] * a[1][2] + iT[11] * a[8][2] - iT[13] * a[7][2] - iT[24] * a[4][3] + iT[1] * a[1][5] + iT[10] * a[8][5] - iT[14] * a[7][5] - iT[23] * a[4][0] + iT[2] * a[5][2] + iT[9] * a[9][2] + iT[15] * a[7][3] - iT[22] * a[2][3] + iT[3] * a[5][5] + iT[8] * a[9][5] + iT[16] * a[7][0] - iT[21] * a[2][0] + iT[4] * a[8][1] + iT[7] * a[9][4] + iT[17] * a[6][4] + iT[20] * a[3][1] + iT[5] * a[8][4] + iT[6] * a[9][1] + iT[18] * a[6][1] + iT[19] * a[3][4] + t[1] + add) >> shift);
    dst[23] = (short)CLIP(-32768, 32767, (iT[0] * a[8][4] + iT[11] * a[9][1] + iT[13] * a[6][1] + iT[24] * a[3][4] - iT[1] * a[8][2] - iT[10] * a[1][2] + iT[14] * a[4][3] + iT[23] * a[7][2] - iT[2] * a[0][1] - iT[9] * a[1][1] + iT[15] * a[3][1] + iT[22] * a[2][1] + iT[3] * a[5][0] + iT[8] * a[9][0] + iT[16] * a[7][5] - iT[21] * a[2][5] - iT[4] * a[9][5] - iT[7] * a[8][0] - iT[17] * a[3][0] - iT[20] * a[6][5] + iT[5] * a[5][2] - iT[6] * a[0][3] - iT[18] * a[4][2] - iT[19] * a[6][2] - t[1] + add) >> shift);
    dst[24] = (short)CLIP(-32768, 32767, (-iT[0] * a[2][3] + iT[11] * a[7][3] + iT[13] * a[5][2] + iT[24] * a[9][2] + iT[1] * a[4][1] + iT[10] * a[7][4] - iT[14] * a[1][4] - iT[23] * a[8][4] - iT[2] * a[4][5] - iT[9] * a[7][0] + iT[15] * a[1][0] + iT[22] * a[8][0] + iT[3] * a[4][3] + iT[8] * a[6][3] + iT[16] * a[0][2] - iT[21] * a[5][3] - iT[4] * a[2][5] - iT[7] * a[3][5] + iT[17] * a[0][5] + iT[20] * a[1][5] + iT[5] * a[2][1] + iT[6] * a[3][1] - iT[18] * a[0][1] - iT[19] * a[1][1] - t[0] + add) >> shift);
    dst[25] = (short)CLIP(-32768, 32767, (-iT[0] * a[4][5] - iT[11] * a[6][5] - iT[13] * a[0][0] + iT[24] * a[5][5] - iT[1] * a[3][1] - iT[10] * a[2][1] + iT[14] * a[1][1] + iT[23] * a[0][1] + iT[2] * a[7][2] + iT[9] * a[4][3] - iT[15] * a[8][2] - iT[22] * a[1][2] + iT[3] * a[6][2] + iT[8] * a[3][3] + iT[16] * a[9][2] + iT[21] * a[8][3] + iT[4] * a[2][4] - iT[7] * a[7][4] - iT[17] * a[5][1] - iT[20] * a[9][1] - iT[5] * a[4][0] - iT[6] * a[6][0] - iT[18] * a[0][5] + iT[19] * a[5][0] - t[0] + add) >> shift);
    dst[26] = (short)CLIP(-32768, 32767, (iT[0] * a[8][0] + iT[11] * a[1][0] - iT[13] * a[4][5] - iT[24] * a[7][0] + iT[1] * a[5][4] + iT[10] * a[9][4] + iT[14] * a[7][1] - iT[23] * a[2][1] - iT[2] * a[1][2] - iT[9] * a[0][2] + iT[15] * a[2][2] + iT[22] * a[3][2] - iT[3] * a[9][2] - iT[8] * a[8][3] - iT[16] * a[3][3] - iT[21] * a[6][2] + iT[4] * a[0][4] - iT[7] * a[5][1] + iT[17] * a[6][1] + iT[20] * a[4][1] + iT[5] * a[8][5] + iT[6] * a[1][5] - iT[18] * a[4][0] - iT[19] * a[7][5] - t[1] + add) >> shift);
    dst[28] = (short)CLIP(-32768, 32767, (-iT[0] * a[5][1] - iT[11] * a[9][1] - iT[13] * a[7][4] + iT[24] * a[2][4] + iT[1] * a[8][2] + iT[10] * a[9][3] + iT[14] * a[6][3] + iT[23] * a[3][2] - iT[2] * a[9][4] - iT[9] * a[8][1] - iT[15] * a[3][1] - iT[22] * a[6][4] + iT[3] * a[9][0] + iT[8] * a[5][0] - iT[16] * a[2][5] + iT[21] * a[7][5] - iT[4] * a[5][5] + iT[7] * a[0][0] + iT[17] * a[4][5] + iT[20] * a[6][5] + iT[5] * a[1][3] + iT[6] * a[0][3] - iT[18] * a[2][3] - iT[19] * a[3][3] + t[1] + add) >> shift);
    dst[29] = (short)CLIP(-32768, 32767, (iT[0] * a[6][4] + iT[11] * a[3][1] + iT[13] * a[9][4] + iT[24] * a[8][1] - iT[1] * a[7][3] - iT[10] * a[4][2] + iT[14] * a[8][3] + iT[23] * a[1][3] - iT[2] * a[3][5] - iT[9] * a[2][5] + iT[15] * a[1][5] + iT[22] * a[0][5] + iT[3] * a[2][4] + iT[8] * a[3][4] - iT[16] * a[0][4] - iT[21] * a[1][4] + iT[4] * a[4][3] + iT[7] * a[7][2] - iT[17] * a[1][2] - iT[20] * a[8][2] - iT[5] * a[3][0] - iT[6] * a[6][5] - iT[18] * a[8][0] - iT[19] * a[9][5] + t[0] + add) >> shift);
    dst[30] = (short)CLIP(-32768, 32767, (-iT[0] * a[7][2] + iT[11] * a[2][2] - iT[13] * a[9][3] - iT[24] * a[5][3] - iT[1] * a[6][0] - iT[10] * a[4][0] + iT[14] * a[5][0] - iT[23] * a[0][5] - iT[2] * a[4][2] - iT[9] * a[6][2] - iT[15] * a[0][3] + iT[22] * a[5][2] + iT[3] * a[2][0] - iT[8] * a[7][0] - iT[16] * a[5][5] - iT[21] * a[9][5] + iT[4] * a[7][1] - iT[7] * a[2][1] + iT[17] * a[9][4] + iT[20] * a[5][4] + iT[5] * a[6][1] + iT[6] * a[4][1] - iT[18] * a[5][1] + iT[19] * a[0][4] + t[0] + add) >> shift);
    dst[31] = (short)CLIP(-32768, 32767, (iT[0] * a[8][5] + iT[11] * a[1][5] - iT[13] * a[4][0] - iT[24] * a[7][5] - iT[1] * a[1][0] - iT[10] * a[8][0] + iT[14] * a[7][0] + iT[23] * a[4][5] - iT[2] * a[8][4] - iT[9] * a[1][4] + iT[15] * a[4][1] + iT[22] * a[7][4] + iT[3] * a[1][1] + iT[8] * a[8][1] - iT[16] * a[7][1] - iT[21] * a[4][4] + iT[4] * a[8][3] + iT[7] * a[1][3] - iT[17] * a[4][2] - iT[20] * a[7][3] - iT[5] * a[1][2] - iT[6] * a[8][2] + iT[18] * a[7][2] + iT[19] * a[4][3] + t[1] + add) >> shift);

    dst[2] = (short)CLIP(-32768, 32767, (iT[4] * b[0] + iT[9] * b[1] + iT[14] * b[2] + iT[19] * b[3] + iT[24] * b[4] + iT[29] * b[5] + add) >> shift);
    dst[7] = (short)CLIP(-32768, 32767, (-iT[14] * b[0] - iT[29] * b[1] - iT[19] * b[2] - iT[4] * b[3] + iT[9] * b[4] + iT[24] * b[5] + add) >> shift);
    dst[12] = (short)CLIP(-32768, 32767, (iT[24] * b[0] + iT[14] * b[1] - iT[9] * b[2] - iT[29] * b[3] - iT[4] * b[4] + iT[19] * b[5] + add) >> shift);
    dst[17] = (short)CLIP(-32768, 32767, (-iT[29] * b[0] + iT[4] * b[1] + iT[24] * b[2] - iT[9] * b[3] - iT[19] * b[4] + iT[14] * b[5] + add) >> shift);
    dst[22] = (short)CLIP(-32768, 32767, (iT[19] * b[0] - iT[24] * b[1] + iT[4] * b[2] + iT[14] * b[3] - iT[29] * b[4] + iT[9] * b[5] + add) >> shift);
    dst[27] = (short)CLIP(-32768, 32767, (-iT[9] * b[0] + iT[19] * b[1] - iT[29] * b[2] + iT[24] * b[3] - iT[14] * b[4] + iT[4] * b[5] + add) >> shift);

    dst[6] = (short)CLIP(-32768, 32767, (iT[12] * c[0] + iT[25] * c[1] + add) >> shift);
    dst[19] = (short)CLIP(-32768, 32767, (-iT[25] * c[0] + iT[12] * c[1] + add) >> shift);
    src++;
    dst += 32;
  }

  if (skip_line)
  {
    memset(dst, 0, (skip_line * 32) * sizeof(int16_t));
  }
}

static void fastForwardDCT8_B8(const int16_t *src, int16_t *dst, int32_t shift, int line, int skip_line, int skip_line2)
{
  const int tr_size = 8;
  const int32_t rnd_factor = 1 << (shift - 1);
  const int  reduced_line = line - skip_line;
  const int  cutoff = tr_size - skip_line2;
  int16_t *p_coef;

  for (int i = 0; i < reduced_line; i++)
  {
    p_coef = dst;
    const int16_t *iT = uvg_g_DCT8P8;
    for (int j = 0; j < cutoff; j++)
    {
      int32_t sum = 0;
      for (int k = 0; k < tr_size; k++)
      {
        sum += src[k] * iT[k];
      }
      p_coef[i] = (sum + rnd_factor) >> shift;
      p_coef += line;
      iT += tr_size;
    }
    src += tr_size;
  }

  if (skip_line)
  {
    p_coef = dst + reduced_line;
    for (int j = 0; j < cutoff; j++)
    {
      memset(p_coef, 0, sizeof(int16_t) * skip_line);
      p_coef += line;
    }
  }

  if (skip_line2)
  {
    p_coef = dst + line * cutoff;
    memset(p_coef, 0, sizeof(int16_t) * line * skip_line2);
  }
}

static void fastInverseDCT8_B8(const int16_t *src, int16_t *dst, int32_t shift, int line, int skip_line, int skip_line2)
{
  const int tr_size = 8;
  const int32_t rnd_factor = 1 << (shift - 1);
  const int  reduced_line = line - skip_line;
  const int  cutoff = tr_size - skip_line2;
  const int16_t *iT = uvg_g_DCT8P8;

  for (int i = 0; i < reduced_line; i++)
  {
    for (int j = 0; j < tr_size; j++)
    {
      int32_t sum = 0;
      for (int k = 0; k < cutoff; k++)
      {
        sum += src[k*line + i] * iT[k*tr_size + j];
      }
      dst[i*tr_size + j] = (short)CLIP(-32768, 32767, (sum + rnd_factor) >> shift);
    }
  }

  if (skip_line)
  {
    memset(dst + (reduced_line*tr_size), 0, (skip_line*tr_size) * sizeof(int16_t));
  }
}


static void fastForwardDST7_B8(const int16_t *src, int16_t *dst, int32_t shift, int line, int skip_line, int skip_line2)
{
  const int tr_size = 8;
  const int32_t rnd_factor = 1 << (shift - 1);
  const int  reduced_line = line - skip_line;
  const int  cutoff = tr_size - skip_line2;
  int16_t *p_coef;

  for (int i = 0; i < reduced_line; i++)
  {
    p_coef = dst;
    const int16_t *iT = uvg_g_DST7P8;
    for (int j = 0; j < cutoff; j++)
    {
      int32_t sum = 0;
      for (int k = 0; k < tr_size; k++)
      {
        sum += src[k] * iT[k];
      }
      p_coef[i] = (sum + rnd_factor) >> shift;
      p_coef += line;
      iT += tr_size;
    }
    src += tr_size;
  }

  if (skip_line)
  {
    p_coef = dst + reduced_line;
    for (int j = 0; j < cutoff; j++)
    {
      memset(p_coef, 0, sizeof(int16_t) * skip_line);
      p_coef += line;
    }
  }

  if (skip_line2)
  {
    p_coef = dst + line * cutoff;
    memset(p_coef, 0, sizeof(int16_t) * line * skip_line2);
  }
}

static void fastInverseDST7_B8(const int16_t *src, int16_t *dst, int32_t shift, int line, int skip_line, int skip_line2)
{
  const int tr_size = 8;
  const int32_t rnd_factor = 1 << (shift - 1);
  const int  reduced_line = line - skip_line;
  const int  cutoff = tr_size - skip_line2;
  const int16_t *iT = uvg_g_DST7P8;

  for (int i = 0; i < reduced_line; i++)
  {
    for (int j = 0; j < tr_size; j++)
    {
      int32_t sum = 0;
      for (int k = 0; k < cutoff; k++)
      {
        sum += src[k*line + i] * iT[k*tr_size + j];
      }
      dst[i*tr_size + j] = (short)CLIP(-32768, 32767, (sum + rnd_factor) >> shift);
    }
  }

  if (skip_line)
  {
    memset(dst + (reduced_line*tr_size), 0, (skip_line*tr_size) * sizeof(int16_t));
  }
}





#define DCT_MTS_NXN_GENERIC(t, n) \
static void fastForward ## t ## _B ## n (const int16_t *src, int16_t *dst, int32_t shift, int line, int skip_line, int skip_line2) {\
\
  const int tr_size = n;\
  const int32_t rnd_factor = 1 << (shift - 1);\
  const int reduced_line = line - skip_line;\
  const int cutoff = tr_size - skip_line2;\
  int16_t *p_coef;\
\
  for (int i = 0; i < reduced_line; i++) \
  {\
    p_coef = dst;\
    const int16_t* iT = uvg_g_ ## t ## P ## n ;\
    for (int j = 0; j < cutoff; j++) \
    {\
      int32_t sum = 0;\
      for (int k = 0; k < tr_size ; k++) \
      {\
        sum += src[k] * iT[k];\
      }\
      p_coef[i] = (sum + rnd_factor) >> shift;\
      p_coef += line;\
      iT += tr_size;\
    }\
    src += tr_size;\
  }\
  if (skip_line) {\
    p_coef = dst + reduced_line;\
    for (int32_t j = 0; j < cutoff; j++) {\
      memset(p_coef, 0, sizeof(int16_t) * skip_line);\
      p_coef += line;\
    }\
  }\
  if (skip_line2) {\
    p_coef = dst + line * cutoff;\
    memset(p_coef, 0, sizeof(int32_t) * line * skip_line2);\
  }\
}

#define IDCT_MTS_NXN_GENERIC(t, n) \
static void fastInverse ## t ## _B ## n (const int16_t *src, int16_t *dst, int32_t shift, int line, int skip_line, int skip_line2) {\
\
  const int tr_size = n;\
  const int32_t rnd_factor = 1 << (shift - 1);\
  const int reduced_line = line - skip_line;\
  const int cutoff = tr_size - skip_line2;\
  const int16_t* iT = uvg_g_ ## t ## P ## n ;\
\
  for (int i = 0; i < reduced_line; i++)\
  {\
    for (int j = 0; j < tr_size; j++)\
    {\
      int32_t sum = 0;\
      for (int k = 0; k < cutoff; k++)\
      {\
        sum += src[k * line + i] * iT[k * tr_size + j];\
      }\
      dst[i * tr_size + j] = (short)CLIP(-32768, 32767, (sum + rnd_factor) >> shift);\
    }\
  }\
\
  if (skip_line)\
  {\
    memset(dst + (reduced_line * tr_size), 0, (skip_line * tr_size) * sizeof(int16_t));\
  }\
}


// DCT 8
//IDCT_MTS_NXN_GENERIC(DCT8, 8);
//IDCT_MTS_NXN_GENERIC(DCT8, 16);
//IDCT_MTS_NXN_GENERIC(DCT8, 32);

//DCT_MTS_NXN_GENERIC(DCT8, 8);
//DCT_MTS_NXN_GENERIC(DCT8, 16);
//DCT_MTS_NXN_GENERIC(DCT8, 32);
/*
// DCT 5
IDCT_MTS_NXN_GENERIC(DCT5, 4);
IDCT_MTS_NXN_GENERIC(DCT5, 8);
IDCT_MTS_NXN_GENERIC(DCT5, 16);
IDCT_MTS_NXN_GENERIC(DCT5, 32);

DCT_MTS_NXN_GENERIC(DCT5, 4);
DCT_MTS_NXN_GENERIC(DCT5, 8);
DCT_MTS_NXN_GENERIC(DCT5, 16);
DCT_MTS_NXN_GENERIC(DCT5, 32);

// DST 1
IDCT_MTS_NXN_GENERIC(DST1, 8);
IDCT_MTS_NXN_GENERIC(DST1, 16);
IDCT_MTS_NXN_GENERIC(DST1, 32);

DCT_MTS_NXN_GENERIC(DST1, 8);
DCT_MTS_NXN_GENERIC(DST1, 16);
DCT_MTS_NXN_GENERIC(DST1, 32);
*/
// DST 7
//IDCT_MTS_NXN_GENERIC(DST7, 8);
//IDCT_MTS_NXN_GENERIC(DST7, 16);
//IDCT_MTS_NXN_GENERIC(DST7, 32);

//DCT_MTS_NXN_GENERIC(DST7, 8);
//DCT_MTS_NXN_GENERIC(DST7, 16);
//DCT_MTS_NXN_GENERIC(DST7, 32);


typedef void partial_tr_func(const int16_t*, int16_t*, int32_t, int, int, int);

// ToDo: Enable MTS 2x2 and 64x64 transforms
static partial_tr_func* dct_table[3][6] = {
  { fastForwardDCT2_B2, fastForwardDCT2_B4, fastForwardDCT2_B8, fastForwardDCT2_B16, fastForwardDCT2_B32, NULL },
  { NULL,               fastForwardDCT8_B4, fastForwardDCT8_B8, fastForwardDCT8_B16, fastForwardDCT8_B32, NULL },
  { NULL,               fastForwardDST7_B4, fastForwardDST7_B8, fastForwardDST7_B16, fastForwardDST7_B32, NULL },
};

static partial_tr_func* idct_table[3][6] = {
  { fastInverseDCT2_B2, fastInverseDCT2_B4, fastInverseDCT2_B8, fastInverseDCT2_B16, fastInverseDCT2_B32, NULL/*fastInverseDCT2_B64*/ },
  { NULL,               fastInverseDCT8_B4, fastInverseDCT8_B8, fastInverseDCT8_B16, fastInverseDCT8_B32, NULL },
  { NULL,               fastInverseDST7_B4, fastInverseDST7_B8, fastInverseDST7_B16, fastInverseDST7_B32, NULL },
};


static const tr_type_t mts_subset_intra[4][2] = { { DST7, DST7 }, { DCT8, DST7 }, { DST7, DCT8 }, { DCT8, DCT8 } };
//static const tr_type_t mts_subset_inter[2] = { DCT8, DST7 };


void uvg_get_tr_type(
  int8_t width,
  int8_t height,
  color_t color,
  const cu_info_t* tu,
  tr_type_t* hor_out,
  tr_type_t* ver_out,
  const int8_t mts_type)
{
  *hor_out = DCT2;
  *ver_out = DCT2;

  if (color != COLOR_Y)
  {
    return;
  }

  const bool explicit_mts = mts_type == UVG_MTS_BOTH || (tu->type == CU_INTRA ? mts_type == UVG_MTS_INTRA : (mts_type == UVG_MTS_INTER && tu->type == CU_INTER));
  const bool implicit_mts = tu->type == CU_INTRA && (mts_type == UVG_MTS_IMPLICIT || mts_type == UVG_MTS_INTER);

  assert(!(explicit_mts && implicit_mts));
  const bool is_isp = tu->type == CU_INTRA && tu->intra.isp_mode && color == COLOR_Y ? tu->intra.isp_mode : 0;
  const int8_t lfnst_idx = color == COLOR_Y ? tu->lfnst_idx : tu->cr_lfnst_idx;
  // const bool is_sbt = cu->type == CU_INTER && tu->sbt && color == COLOR_Y; // TODO: check SBT here when implemented

  if (is_isp && lfnst_idx) {
    return;
  }

  if (implicit_mts || (is_isp && explicit_mts))
  {
    bool width_ok = width >= 4 && width <= 16;
    bool height_ok = height >= 4 && height <= 16;

    if (width_ok)
    {
      *hor_out = DST7;
    }
    if (height_ok)
    {
      *ver_out = DST7;
    }
    return;
  }

  /*
  TODO: SBT HANDLING
  */

  if (explicit_mts)
  {
    if (tu->tr_idx > MTS_SKIP) {
      *hor_out = mts_subset_intra[tu->tr_idx - MTS_DST7_DST7][0];
      *ver_out = mts_subset_intra[tu->tr_idx - MTS_DST7_DST7][1];
    }
  }
}


static void mts_dct_generic(
  const int8_t bitdepth,
  const color_t color,
  const cu_info_t* tu,
  const int8_t width,
  const int8_t height,
  const int16_t* input,
  int16_t* output,
  const int8_t mts_type)
{
  tr_type_t type_hor;
  tr_type_t type_ver;

  uvg_get_tr_type(width, height, color, tu, &type_hor, &type_ver, mts_type);

  if (type_hor == DCT2 && type_ver == DCT2 && !tu->lfnst_idx && !tu->cr_lfnst_idx && width == height)
  {
    dct_func *dct_func = uvg_get_dct_func(width, height, color, tu->type);
    dct_func(bitdepth, input, output);
  }
  else
  {
    int skip_width = (type_hor != DCT2 && width == 32) ? 16 : (width > 32 ? width - 32 : 0);
    int skip_height = (type_ver != DCT2 && height == 32) ? 16 : (height > 32 ? height - 32 : 0);
    const int log2_width_minus1  = uvg_g_convert_to_log2[width] - 1;
    const int log2_height_minus1 = uvg_g_convert_to_log2[height] - 1;
    //const int log2_width_minus2 = uvg_g_convert_to_bit[width];
    //const int log2_height_minus2 = uvg_g_convert_to_bit[height];

    if((tu->lfnst_idx && color == COLOR_Y) || (tu->cr_lfnst_idx && color != COLOR_Y)) {
      if ((width == 4 && height > 4) || (width > 4 && height == 4))
      {
        skip_width = width - 4;
        skip_height = height - 4;
      }
      else if ((width >= 8 && height >= 8))
      {
        skip_width = width - 8;
        skip_height = height - 8;
      }
    }

    partial_tr_func* dct_hor = width != 1 ? dct_table[type_hor][log2_width_minus1] : NULL;
    partial_tr_func* dct_ver = height != 1 ? dct_table[type_ver][log2_height_minus1] : NULL;

    int16_t tmp[32 * 32];
    const int32_t shift_1st = log2_width_minus1 + bitdepth - 8;
    const int32_t shift_2nd = log2_height_minus1 + 7;
    if (height == 1) {
      dct_hor(input, output, shift_1st, height, 0, skip_width);
    } else if (width == 1) {
      dct_ver(input, output, log2_height_minus1 + 1 + bitdepth + 6 - 15, width, 0, skip_height);
    } else {
      dct_hor(input, tmp, shift_1st, height, 0, skip_width);
      dct_ver(tmp, output, shift_2nd, width, skip_width, skip_height);
    }    
  }
}


static void mts_idct_generic(
  const int8_t bitdepth,
  const color_t color,
  const cu_info_t* tu,
  const int8_t width,
  const int8_t height,
  const int16_t* input,
  int16_t* output,
  const int8_t mts_type)
{
  tr_type_t type_hor;
  tr_type_t type_ver;

  uvg_get_tr_type(width, height, color, tu, &type_hor, &type_ver, mts_type);

  if (type_hor == DCT2 && type_ver == DCT2 && !tu->lfnst_idx && !tu->cr_lfnst_idx && width == height)
  {
    dct_func *idct_func = uvg_get_idct_func(width, height, color, tu->type);
    idct_func(bitdepth, input, output);
  }
  else
  {
    int skip_width = (type_hor != DCT2 && width == 32) ? 16 : width > 32 ? width - 32 : 0;
    int skip_height = (type_ver != DCT2 && height == 32) ? 16 : height > 32 ? height - 32 : 0;
    const int log2_width_minus1  = uvg_g_convert_to_log2[width] - 1;
    const int log2_height_minus1 = uvg_g_convert_to_log2[height] - 1;

    if ((tu->lfnst_idx && color == COLOR_Y) || (tu->cr_lfnst_idx && color != COLOR_Y)) {
      if ((width == 4 && height > 4) || (width > 4 && height == 4)) {
        skip_width = width - 4;
        skip_height = height - 4;
      }
      else if ((width >= 8 && height >= 8)) {
        skip_width = width - 8;
        skip_height = height - 8;
      }
    }

    partial_tr_func* idct_hor = width != 1 ? idct_table[type_hor][log2_width_minus1] : NULL;
    partial_tr_func* idct_ver = height != 1 ? idct_table[type_ver][log2_height_minus1] : NULL;

    int16_t tmp[32 * 32];
    const int max_log2_tr_dynamic_range = 15;
    const int transform_matrix_shift = 6;

    const int32_t shift_1st = transform_matrix_shift + 1;
    const int32_t shift_2nd = (transform_matrix_shift + max_log2_tr_dynamic_range - 1) - bitdepth;

    if (height == 1) {
      idct_hor(input, output, shift_2nd + 1, height, 0, skip_width);
    } else if (width == 1) {
      idct_ver(input, output, shift_2nd + 1, width, 0, skip_height);
    } else {
      idct_ver(input, tmp, shift_1st, width, skip_width, skip_height);
      idct_hor(tmp, output, shift_2nd, height, 0, skip_width);
    }
  }
}


int uvg_strategy_register_dct_generic(void* opaque, uint8_t bitdepth)
{
  bool success = true;

  success &= uvg_strategyselector_register(opaque, "fast_forward_dst_4x4", "generic", 0, &fast_forward_dst_4x4_generic);

  success &= uvg_strategyselector_register(opaque, "dct_4x4", "generic", 0, &dct_4x4_generic);
  success &= uvg_strategyselector_register(opaque, "dct_8x8", "generic", 0, &dct_8x8_generic);
  success &= uvg_strategyselector_register(opaque, "dct_16x16", "generic", 0, &dct_16x16_generic);
  success &= uvg_strategyselector_register(opaque, "dct_32x32", "generic", 0, &dct_32x32_generic);
  //success &= uvg_strategyselector_register(opaque, "dct_non_square", "generic", 0, &dct_non_square_generic);

  success &= uvg_strategyselector_register(opaque, "fast_inverse_dst_4x4", "generic", 0, &fast_inverse_dst_4x4_generic);

  success &= uvg_strategyselector_register(opaque, "idct_4x4", "generic", 0, &idct_4x4_generic);
  success &= uvg_strategyselector_register(opaque, "idct_8x8", "generic", 0, &idct_8x8_generic);
  success &= uvg_strategyselector_register(opaque, "idct_16x16", "generic", 0, &idct_16x16_generic);
  success &= uvg_strategyselector_register(opaque, "idct_32x32", "generic", 0, &idct_32x32_generic);

  success &= uvg_strategyselector_register(opaque, "mts_dct", "generic", 0, &mts_dct_generic);
  success &= uvg_strategyselector_register(opaque, "mts_idct", "generic", 0, &mts_idct_generic);

  return success;
}
